非同期ラムダによる並列 foreach 質問する

非同期ラムダによる並列 foreach 質問する

コレクションを並列に処理したいのですが、実装に問題があり、助けていただければ幸いです。

問題は、並列ループのラムダ内で 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投稿

おすすめ記事