linq select での非同期待機 質問する

linq select での非同期待機 質問する

既存のプログラムを変更する必要があり、次のコードが含まれています。

var inputs = events.Select(async ev => await ProcessEventAsync(ev))
                   .Select(t => t.Result)
                   .Where(i => i != null)
                   .ToList();

しかし、これは私にとって非常に奇妙に思えます。まず第一に、selectでのasyncandの使用です。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

おすすめ記事