6

ソケット接続を介してさまざまなサイズのシリアル化可能なオブジェクトを送信するアプリがありますが、可能な限りスケーラブルにしたいと考えています。また、数十から数百もの接続が存在する可能性があります。

  1. NetworkStreamは、着信メッセージを継続的にリッスンしているTcpClientから送信されます。
  2. 標準のNetworkStream.Read()でスレッドをブロックしたくありません。これはスケーリングする必要があります。これは、この種のクラスのかなり標準的な動作であり、クラスにReadTimeoutプロパティがあるため、Read()ブロックのみを想定しています。
  3. BinaryFormatterがRead()を使用するだけなのか、それともAsyncの一部を内部で実行するのかはわかりません。私の推測は違います。
  4. TcpClientはメッセージを取得し、最後まで読んでから、メッセージのリッスンに戻る必要があります。

ですから、この猫の皮を剥ぐ方法は多すぎるようです。実際に何が最も効率的かはわかりません。私は:

BinaryFormatterを使用してNetworkStreamを読み取るだけですか?

var netStream = client.GetStream();
var formatter = new BinaryFormatter();
var obj = formatter.Deserialize(netStream);

または、新しいasync / awaitで魔法をかけましょう:

using(var ms = new MemoryStream()) 
{
   var netStream = client.GetStream();
   var buffer = new byte[1028];
   int bytesRead;
   while((bytesRead = await netStream.ReadAsync(buffer, 0, buffer.length)) > 0) {
      ms.Write(buffer, 0, buffer.Length);
   }
   var formatter = new BinaryFormatter();
   var obj = formatter.Deserialize(ms);
}

または上記と同様に、新しいCopyToAsyncメソッドのみを利用します。

using(var ms = new MemoryStream()) 
{
   var netStream = client.GetStream();
   await netStream.CopyToAsync(ms); //4096 default buffer.
   var formatter = new BinaryFormatter();
   var obj = formatter.Deserialize(ms);
}

または何か他のもの?

最もスケーラビリティ/効率性を提供する答えを探しています。

[注:上記はすべてPSUEDOコードであり、例として示されています]

4

4 に答える 4

5

最初のアプローチには、大きなストリームで問題があります。大きなデータを送信する場合、そのコードはメモリ不足の例外でアプリケーションを爆破します。

2番目のアプローチは非常によく見えます-非同期であり(読み取りが完了するのを待つためにいくつかの貴重なスレッドを使用しないことを意味します)、データのチャンクを使用します(これはストリームを操作する方法です)。

したがって、2番目のオプションを選択します。おそらくわずかな変更を加えます。一度にデータのチャンクのみを逆シリアル化し、全体を読み取らないでください(ストリームの長さが完全に確実でない限り)。

これが私が考えていることです(擬似コード)

using (var networkStream = client.GetStream()) //get access to stream
{
    while(!networkStream.EndOfStream) //still has some data
    {
        var buffer = new byte[1234]; //get a buffer
        await SourceStream.ReadAsync(result, 0, buffer); //read from network there

        //om nom nom buffer     
        Foo obj;
        using(var ms = new MemoryStream()) //process just one chunk
        {
             ms.Write(buffer, 0, buffer.Length);
             var formatter = new BinaryFormatter();
             obj = formatter.Deserialize(ms);   //desserialise the object        
        } // dispose memory

        //async send obj up for further processing
    }
}
于 2013-01-08T20:40:04.920 に答える
2

async / awaitのものを使用すると、リソースを待機しているときにスレッドをブロックする頻度が少なくなるため、一般に、スレッドブロックバージョンよりも拡張性が高くなります。

于 2013-01-08T20:38:16.760 に答える
2

何百もの同時操作が実行されている場合、非同期はより適切にスケーリングされます。

ただし、シリアルでは遅くなります。非同期には、ベンチマークで簡単に検出できるオーバーヘッドがあります。オプション2が必要ない場合は、オプション1を使用することをお勧めします。

于 2013-01-08T20:45:10.467 に答える
1

クライアントの観点から、非同期にすることと同期することには違いがあることにも言及する価値があると思いました。非同期にすると...一般的に誰もが同じ応答時間を経験します。したがって、すべての要求が集中的に行われると、誰もが応答時間が遅くなることに気付くでしょう。同期リクエストを使用すると、リクエストが簡単なユーザーは、他のユーザーに邪魔されないため、はるかに高速に処理されます。ただし、同期環境に多数の同時リクエストがある場合、最終的にはすべてのスレッドがブロックされ、リクエストが応答を受け取らない可能性があります。

于 2013-01-08T21:55:56.450 に答える