3

ノード数のセットを取得するには、Web サービスを一連の呼び出しを行う必要があります。私はすべての呼び出しを並行して非同期に行っています。呼び出しを開始した後、次のように結果を合計します。

//pendingTasks is List<Task<int>>
int sum = 0;
foreach (var task in pendingTasks)
{
    sum += await task;
    if (sum > 100) break;
}

100を超えた後の特定のカウントは気にしないので、ブレークがあります。

まず、そのようなループから抜け出すのは危険ですか?保留中のタスクを残すのは悪いことですか? あらゆる種類のメモリリークが発生しますか?

第二に、個々の呼び出しはかなり一貫性がありません。最初の呼び出しが最も長く、その後のすべての呼び出しの合計が 100 を超えていたとしても、それを待つことになるのは嫌です。受け取った順番。私はWhenAll以前に使用WhenAnyしたことがありますが、それが私が望むものであると確信していますが、この種のシナリオで使用する方法がよくわかりません。 .

4

2 に答える 2

4

まず、そのようにループから抜け出すのは危険ですか?保留中のタスクを残すのは悪いことですか?それはどんな種類のメモリリークも引き起こしますか?

メモリリークは発生しませんが、タスクにキャンセルトークンが関連付けられている場合は、余分な作業が不必要に行われるのを防ぐために、タスクをキャンセルすると便利です。

.NET 4では、障害が発生したが、それらの障害が「監視」されていないタスクは、デフォルトで(意図的に)プロセスを停止しますが、これは.NET4.5では緩和されています。

私は以前にWhenAllを使用したことがあり、WhenAnyが私が望むものであると確信していますが、この種のシナリオでそれを使用する方法がよくわかりません。全部終わった。

WhenAnyここでは確かにうまくいく可能性がありますが、別のアプローチは、タスクを「魔法のように」並べ替えて、タスクが完了する順序でタスクを繰り返すことができるようにすることです。むしろ、元のタスクと同じ結果が得られる新しいタスクを、完了する順序で繰り返します。

私はそのトピックについて少し前にブログ投稿を書きましたが、それは私の考えではありませんでした。基本的に、元のタスクごとに1つずつ、一連​​のオブジェクトを作成し、TaskCompletionSource元の各タスクに継続を追加して、「次に利用可能な」タスク完了ソースにデータを入力します。

の使用方法の例として、私の多数決WhenAnyのブログ投稿を見ることができますが、その欠点は、コレクションの操作が非常に多く、を呼び出すことです。「魔法の並べ替え」は、タスクの新しいコレクションを1つ作成しますが、元の各タスクに継続を添付するだけなので、実際にすべてのタスクを待つものはありません...一度に1つずつ繰り返し、それぞれを待つことができます。順番に1つ。nWhenAny

于 2012-09-26T16:37:11.767 に答える
1

Jon Skeet の答えと Stephen Toub のアプローチへのリンクはどちらも素晴らしいです。

BufferBlock<int>別の方法は、TPL DataFlow ライブラリのを使用することです。タスクのパラメーターを編集するアクセス権があれば、単純に aBufferBlockPost結果を渡すことができます。

var buffer = new BufferBlock<int>();

//Run your tasks somehow like so:
YourAsyncFunctionThatPostsAnInt(buffer, cancellationTokenSource.Token)
...

int sum = 0;
while(sum < 100)
{
    sum += await buffer.ReceiveAsync()
}

buffer.Complete();
cancellationTokenSource.Cancel();

Post既存のタスクでも、それらの継続を結果にバッファに追加できます。キャンセル トークンは、それらの実行を回避するための最良の方法です。

于 2012-09-26T21:03:20.500 に答える