2011-02-10 8 views
2

私は、次のコードを使用して、可能な限り私のUDPデータ収集ソケットからできるだけ多く絞るしようとしていますよ:高性能UDPサービス.NET

public void Start() 
{ 

    if (socket == null) Open(); 
    this.stats.PositionServerStarted = DateTime.Now; 
    this.state = SocketWorkerState.Running; 
    AsyncBeginReceive(); 
} 

private void AsyncBeginReceive() 
{ 
    DataPacket dataPacket = new DataPacket(socket, this.settings.IPAddress, 
     this.settings.Port, SocketWorker.MaxDataRead); 
    Interlocked.Increment(ref stats.ProcessingThreads); 
    socket.BeginReceiveFrom(dataPacket.BytePacket, 0, 
     SocketWorker.MaxDataRead, SocketFlags.None, 
     ref dataPacket.RemoteEndPoint, new AsyncCallback(AsyncEndReceive), 
     dataPacket); 
} 

private void AsyncEndReceive(IAsyncResult ar) 
{ 
    DataPacket dataPacket= null; 
    AsyncBeginReceive(); 
    dataPacket = (DataPacket)ar.AsyncState; 
    dataPacket.EnteredQueue = DateTime.Now; 
    dataPacket.DataLength= dataPacket.SourceSocket.EndReceiveFrom(ar, 
     ref dataPacket.RemoteEndPoint); 
    Interlocked.Decrement(ref stats.ProcessingThreads); 
    Interlocked.Increment(ref this.stats.PacketsQueued); 
    ThreadPool.QueueUserWorkItem(new WaitCallback(OnPacketArrived), 
     dataPacket); 
    Interlocked.Decrement(ref this.stats.PacketsQueued); 
} 

private void OnPacketArrived(object packet) 
{ 
    //go ahead and process the packet 
} 

誰もがこれを改善する方法上の任意のアイデアを持っていますか? AsyncEndReceive()からAsyncBeginReceive()をベストプラクティスと呼んでいますか?

私は

ThreadPool.SetMinThreads(20,20); 
ThreadPool.SetMaxThreads(250, 250); 

にスレッドプールを微調整してきました。しかし、私は正直だ場合、これは、パフォーマンスに大きな影響を持つように表示されません。

答えて

1

個人的には、起動時に複数のrecvを投稿すると、AsyncBeginReceive()が調整可能な回数呼び出されます。そうすれば、1つのrecvが完了してから次のrecvが始まるまで待つ必要はありません。管理されていない用語では、I/Oサブシステムが可能であればバッファに直接読み込むことができるように、常に非同期読み取りが保留されていることをお勧めします。これは高性能に変換されても変換されなくてもかまいませんが、 。

また、ソケットのrecvバッファーサイズを大きくすると、データグラムが破棄されないようにすることもできます。

スレッドプールの設定を調整する必要はないでしょうか。アンマネージコードでは、async I/Oを使用して、完全にロードされたネットワークパイプ(< 5スレッド程度)を扱うことができます。あなたのうちの250がマークから離れています。

+0

msyncでAsyncBeginReceive()を見つけることができません。あなたが提案できる参考資料はありますか?ありがとう。 –

+0

元の質問のコードのメソッドです。おそらくあなたが使いたいと思う 'socket.BeginReceiveFrom()'を呼び出します:) –

0

あなたが持っているものが十分に機能していない場合にのみ最適化し、最適化する必要がある場合は、指標に基づいて最適化してください。

請求、私は、このアプローチは、単にReceiveFrom内のブロックは、次にI非同期の両方の使用を回避する、同期各パケットの処理を完了したことをループ内 N + 1スレッドを有するよりも、それ以上有効であることを確信していません/ Oおよびスレッド間キューイング。ボトルネックデバイスの数(通常はプロセッサコアですが、I/Oが大量にかかっている場合はスピンドルも限られたリソースになる可能性があります)、あるいはその両方をカウントするのに nを設定してください。 "+ 1"部分は、スレッドが何か他のことをしているときに、負荷のかかっているデバイスのアイドリングを避けるためだけです。

ThreadPoolBeginXxxベースの非同期I/O(.Net(フルとコンパクトの両方のフレームワーク))で、非常に苦労した経験がありました。そして、やはり、(少なくとも非同期I/Oからの)痛みの多くは、他人のコードが原因であった可能性があります。 ThreadPoolはコンパクトなフレームワークでは信頼できません。 :-)

0

高性能を達成するには、asyncは良い方法ではないと思います。手動で読み込み、各パスで大量のデータを要求します。同時接続数が少ない場合は、ソケットに十分な注意を払うようにスレッドを専用にすることもできます。非同期操作には、直接的な処理に比べて多くのオーバーヘッドがあります。

本当に高いスループットが必要な場合は、スレッドの優先度を設定することを検討してください。また、.Netの優先度は相対的なものなので、process priorityも設定することをお勧めします。

プロジェクトのプロパティの最適化設定は、処理速度が高い場合にパフォーマンスに顕著な影響を与えます。

+1

UDPソケットから '大きなチャンク'を読み取ると、データグラム全体が表示されるか、表示されません。 –

+0

mtuサイズを変更しますか? – AnthonyLambert

+0

ストリームから読みます。小さなブロックサイズを内部的に使用すると、より多くの反復処理が行われます。 OSのコストとそれをバッファするためのすべてのコードが呼び出されるたびに、コストがかかります。また、適切な最適化がなければ、GCはパーティーを持ちます(そして、処理が完了するまで待たなければなりません)...ストリームを処理するための一時的な配列の初期化が一般的すぎます。 –

関連する問題