簡體   English   中英

用NetworkStream.ReadAsync替換Socket.ReceiveAsync(等待)

[英]Replacing Socket.ReceiveAsync with NetworkStream.ReadAsync (awaitable)

我有一個應用程序,它同時生成幾百個TCP連接,並從它們接收一個恆定的數據流。

 private void startReceive()
    {
        SocketAsyncEventArgs e = new SocketAsyncEventArgs();
        e.Completed += receiveCompleted;
        e.SetBuffer(new byte[1024], 0, 1024);
        if (!Socket.ReceiveAsync(e)) { receiveCompleted(this, e); }  
    }

    void receiveCompleted(object sender, SocketAsyncEventArgs e)
    {
        ProcessData(e);

        if (!Socket.ReceiveAsync(e)) { receiveCompleted(this, e); }
    }

我的嘗試導致了這樣的事情:

private async void StartReceive()
    {
        byte[] Buff = new byte[1024];
        int recv = 0;
        while (Socket.Connected)
        {
            recv = await NetworkStream.ReadAsync(Buff, 0, 1024);
            ProcessData(Buff,recv);
        }
    }

我遇到的問題是調用StartReceive()的方法會阻塞,而不是調用StartReceive()調用的伴隨的StartSend() method called after . Creating a new task for . Creating a new task for StartReceive() . Creating a new task for would just end up with 300-ish threads, and it seems to do so just by calling StartReceive()來實現。

在使用NetworkStream ,在我現有代碼上實現新asyncawait關鍵字的正確方法是什么,因此它使用Socket.SendAsync()Socket.ReceiveAsync()使用的線程池來避免必須擁有數百個線程/任務?

以這種方式使用networkstream比使用beginreceive i / o完成端口有任何性能優勢?

你在這里一次改變兩件事:異步樣式( SocketAsyncEventArgsTask / async )和抽象級別( SocketNetworkStream )。

由於您已經熟悉Socket ,我建議只更改異步樣式,並繼續直接使用Socket類。

Async CTP沒有給Socket任何async兼容的方法(這很奇怪;我認為它們被錯誤地遺漏了,並將在.NET 4.5中添加)。

如果您使用我的AsyncEx庫,那么創建自己的ReceiveAsyncTask擴展方法(以及其他操作的類似包裝器) 並不難

public static Task<int> ReceiveAsyncTask(this Socket socket,
    byte[] buffer, int offset, int size)
{
  return AsyncFactory<int>.FromApm(socket.BeginReceive, socket.EndReceive,
      buffer, offset, size, SocketFlags.None);
}

完成后,您的StartReceive可以這樣寫:

private async Task StartReceive()
{
  try
  {
    var buffer = new byte[1024];
    while (true)
    {
      var bytesReceived = await socket.ReceiveAsyncTask(buffer, 0, 1024)
          .ConfigureAwait(false);
      ProcessData(buffer, bytesReceived);
    }
  }
  catch (Exception ex)
  {
    // Handle errors here
  }
}

現在,要解決許多小問題:

  • await不會產生新的線程。 我和其他許多人一樣, 在我的博客上寫了一篇async / await簡介 async / await允許並發,但這並不一定意味着多線程。
  • 數以百計的線程可能會有問題。 但是,數以百計的任務根本不是問題; 線程池和BCL旨在處理許多任務。
  • async / await不是一種全新的異步處理形式; 它只是一種表達異步處理的簡單方法 它仍然使用下面的IOCP。 async / await性能略低於低級方法; 它的吸引力在於編寫和編寫異步方法的簡易性。
  • 一個非常繁忙的系統在切換到async / await時會看到一些GC壓力增加。 並行團隊的Stephen Toub 寫了一些示例套接字特定的等待 ,可以幫助解決這個問題。 (我建議首先使用簡單的模式,如果你認為有必要,只使用性能增強的方法;但是,如果最終需要它,最好知道它在那里)。
  • 異步方法應返回Task除非您確實需要它們返回void Task是可以接受的,因此您的方法是可組合的(並且更容易測試); void更像是“火與忘”。
  • 您可以調用ConfigureAwait(false)來告訴其余的async方法在線程池線程上執行。 我在上面的例子中使用它,以便ProcessData在線程池線程中執行,就像使用SocketAsyncEventArgs
  • Socket.Connected沒用。 您需要發送數據以檢測連接是否仍然有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM