0

必要なのは、非同期操作を順番に実行するクラスです。

class FooSocket
{
    private Socket _Socket;

    // Message is a class that wraps a byte array.
    public Task<Message> Receive() { /*Bla...*/ };
    public Task<int> Send(Message message) { /*Bla...*/ };
}

送信、受信、送信をこの順序で呼び出す場合、最初に送信し、最初の受信が終了するまで残りの受信および送信操作をキューに入れる必要があります。

クラスでメインタスクフィールドを作成して、MainTask = MainTask.ContinueWith(...)ある種のアプローチに従ってみました。私はこれを正確に実行するSequencerというクラスを作成しましたが、継続などでネストされたタスクを作成して(Task.Factory.FromAsyncメソッドを使用して)、どういうわけか間違っていると感じました。

また、TaskCompletionSourceオブジェクトをキューに入れ、Receive / Sendメソッドでそれらのタスクを返し、別のスレッドで無限ループでキューをチェックするようなものを作成しようとしましたが、約200kのFooSocketインスタンスがあるため、それぞれのスレッドも感じました賢明ではありません。スレッドプールにすると、「スレッドプールは長時間の操作には使用しないでください」というルールになります。

私は親密に感じますが、これらの仕事を注文するための最も効率的な方法が何であるかを確信できません。

4

2 に答える 2

2

TPL Dataflowを使用します。NuGet を介して、またはAsync CTPの一部としてインストールできます。TPL Dataflow は、BufferBlock<T>まさに必要なもののように聞こえる基本的な型を提供します。

ソケットをモデル化しているだけのSend場合は、データがバッファリングされて出て行くときにタスクを完了し、別のバッファに継続的にReceive読み取り、そのバッファから読み取るときにタスクを完了します。(注: の「送信」操作はSocket、データがネットワーク上に出たときや宛先に到達したときではなく、データが OS にバッファリングされたときに完了します)。

高レベルのコマンド/応答をモデル化している場合は、James が提案したように、コマンド/応答全体を表す 1 つのタスクが必要です。私は両方を行います。async/awaitサポートを使えば、重ね着も簡単です。(注: での「受信」操作Socketは部分的な受信で完了する場合があるため、メッセージのフレーミングが必要です)。

アーキテクチャにもいくつかの作業が必要になる場合があります。

約 200k の FooSocket インスタンスがあります

それは間違いなく問題です (TCP/IP を使用していると仮定しています)。約 65K の TCP/IP ポートしかなく、デフォルトでは約 16K のみがエフェメラルであり、OS のためにかなりの量の「息抜き」を残す必要があります。そうしないと、OS が誤動作を開始します。(理論的には) 最大 59K になる可能性のあるエフェメラル範囲を変更しない限り、現実的には最大 12K の接続しかないと推定します。一時的な範囲を変更し、ロードバランサーで複数の IP アドレスを使用しない限り、〜 200K は不可能です。

于 2012-07-17T12:54:47.450 に答える
1

それが要求/応答タイプの動作である場合、私見では、タスクの粒度は、送信と受信を分離するのではなく、完全な往復である必要があります。

.net 4 のサポートには CTP は必要ありません。非同期ターゲティング パックを使用できます。

消費コードはどのように見えますか? await 呼び出しのループ?

于 2012-07-17T12:06:35.790 に答える