既存のプログラムを変更する必要があり、次のコードが含まれています。
var inputs = events.Select(async ev => await ProcessEventAsync(ev))
.Select(t => t.Result)
.Where(i => i != null)
.ToList();
しかし、これは私にとって非常に奇妙に思えます。まず第一に、selectでのasync
andの使用です。await
この答えStephen Cleary 著 これらを削除できるはずです。
次に、結果を選択する 2 番目ですSelect
。これは、タスクがまったく非同期ではなく、同期的に実行される (無駄な労力がかかる) ことを意味するのでしょうか、それとも、タスクは非同期的に実行され、完了するとクエリの残りの部分が実行されるのでしょうか。
上記のコードは次のように記述すればよいでしょうか?スティーブン・クリアリーによる別の回答:
var tasks = await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev)));
var inputs = tasks.Where(result => result != null).ToList();
そして、これは完全に同じですか?
var inputs = (await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev))))
.Where(result => result != null).ToList();
このプロジェクトに取り組んでいる間、最初のコード サンプルを変更したいのですが、(明らかに動作している) 非同期コードを変更することにはあまり乗り気ではありません。おそらく、私が心配しているのは無駄で、3 つのコード サンプルはすべてまったく同じことを行っているのでしょうか?
ProcessEventsAsync は次のようになります。
async Task<InputResult> ProcessEventAsync(InputEvent ev) {...}
ベストアンサー1
var inputs = events.Select(async ev => await ProcessEventAsync(ev))
.Select(t => t.Result)
.Where(i => i != null)
.ToList();
しかし、これは私にとっては非常に奇妙に思えます。まず第一に、select での async と await の使用です。Stephen Cleary のこの回答によると、これらを削除できるはずです。
の呼び出しはSelect
有効です。これらの 2 行は本質的に同一です。
events.Select(async ev => await ProcessEventAsync(ev))
events.Select(ev => ProcessEventAsync(ev))
( から同期例外がスローされる方法に関してはわずかな違いがありますProcessEventAsync
が、このコードのコンテキストではまったく問題になりません。)
次に、結果を選択する 2 番目の Select です。これは、タスクがまったく非同期ではなく、同期的に実行される (無駄な労力がかかる) ことを意味するのでしょうか、それとも、タスクは非同期的に実行され、完了するとクエリの残りの部分が実行されるのでしょうか。
これはクエリがブロックされていることを意味します。したがって、実際には非同期ではありません。
詳しく見てみましょう:
var inputs = events.Select(async ev => await ProcessEventAsync(ev))
まず各イベントに対して非同期操作を開始します。次に次の行を実行します。
.Select(t => t.Result)
これらの操作が 1 つずつ完了するまで待機します (最初に最初のイベントの操作を待機し、次に次の操作を待機し、その次の操作を待機するというように)。
これは、ブロックし、例外を でラップするため、気にしない部分ですAggregateException
。
そして、これは完全に同じですか?
var tasks = await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev)));
var inputs = tasks.Where(result => result != null).ToList();
var inputs = (await Task.WhenAll(events.Select(ev => ProcessEventAsync(ev))))
.Where(result => result != null).ToList();
はい、これら 2 つの例は同等です。どちらもすべての非同期操作を開始し ( events.Select(...)
)、すべての操作が任意の順序で完了するまで非同期的に待機し ( await Task.WhenAll(...)
)、残りの作業に進みます ( Where...
)。
これらの例は両方とも元のコードとは異なります。元のコードはブロッキングしており、例外を でラップしますAggregateException
。