コレクションを並列に処理したいのですが、実装に問題があり、助けていただければ幸いです。
問題は、並列ループのラムダ内で C# で async とマークされたメソッドを呼び出す場合に発生します。例:
var bag = new ConcurrentBag<object>();
Parallel.ForEach(myCollection, async item =>
{
// some pre stuff
var response = await GetData(item);
bag.Add(response);
// some post stuff
}
var count = bag.Count;
カウントが 0 になると問題が発生します。これは、作成されたすべてのスレッドが実質的にバックグラウンド スレッドであり、呼び出しParallel.ForEach
が完了を待機しないためです。async キーワードを削除すると、メソッドは次のようになります。
var bag = new ConcurrentBag<object>();
Parallel.ForEach(myCollection, item =>
{
// some pre stuff
var responseTask = await GetData(item);
responseTask.Wait();
var response = responseTask.Result;
bag.Add(response);
// some post stuff
}
var count = bag.Count;
動作しますが、await の賢さが完全に無効になり、手動で例外処理を行う必要があります。(簡潔にするために削除しました)。
Parallel.ForEach
ラムダ内で await キーワードを使用するループを実装するにはどうすればよいですか? 可能ですか?
Parallel.ForEach メソッドのプロトタイプはAction<T>
as パラメーターを受け取りますが、非同期ラムダを待機するようにします。
ベストアンサー1
単純な並列処理だけが必要な場合は、次のようにします。
var bag = new ConcurrentBag<object>();
var tasks = myCollection.Select(async item =>
{
// some pre stuff
var response = await GetData(item);
bag.Add(response);
// some post stuff
});
await Task.WhenAll(tasks);
var count = bag.Count;
もっと複雑なものが必要な場合は、スティーブン・トーブのForEachAsync
投稿。