2012-10-03 26 views
5

私たちは、バックグラウンドでタスクのリストを実行するwebservice関数を持っています。すべてのタスクが完了すると、それが戻ります。やるべきこと、個々のタスクのasync/awaitを使用したマルチスレッド待機の書き換え

var result = new List<int>(); 
var tasks = new List<Task<int>>(); 

foreach (var row in rowlist) 
    tasks.Add(Task.Factory.StartNew(() => DoWork(row))); 
foreach (var task in tasks) 
    result.Add(task.Result); 

task.Result待ち:私は、私は次のコードの作業を取得するために管理してきたC#5のための機能を再訪しました。私はこれを、DoWorkメソッドに3秒の遅延を加え、10秒のタスクのリストのために5秒未満で終了したことを確認することでこれをテストしました。

これで、新しいasync/await構文を使用して関数を書き直そうとしました。しかし、私はそれを動作させるように見えることはできません。コンパイルすると、待機を追加して検証されるので、同期して実行されます。

async/awaitを使用して上記のスニペットを書き換える方法に関するアイデアはありますか?

答えて

9

私はこれを記述します。あなたがそれらをすべてしたいと

var tasks = rowlist.Select(row => Task.Run(() => DoWork(row))); 

var results = (await Task.WhenAll(tasks)).ToList(); 

は基本的に、あなたはまだすぐに開始、タスクにあなたが(awaitを使用せずに)以前になかった方法を作成します。その後、すべてが非同期で完了するのを待つことができます(await Task.WhenAll経由)。そして、結果がすぐに取り出されます。リードCopsey、Servyとステファン・クリアリーの回答やコメントをもとに

+0

これは非同期で実行されます。しかし、結果は 'System.AggregateException'となり、内部例外は' {"クエリの結果を複数回列挙することはできません" – Andomar

+0

もっと重要なのは、 'await'で行を省略すると、なぜこれが同期して実行されるのでしょうか? – Andomar

+1

@Andomarタスクを作成するときに 'Select'の後に' ToList'を呼び出します。それはエラーを修正するはずです。現在、 'tasks'を数回列挙すると、新しいタスクを2回作成しようとしますが、これは悪いことです。 – Servy

2

私は、このソリューションに進行してきました:

var results = rowlist 
    .Select(row => Task.Run(() => DoWork(row))) 
    .ToList() 
    .Select(t => t.Result); 

Selectは終了するタスクに待機します。ストリーミングを防止するために、間にToList()を追加しましたが、それがなくても動作するようです。

+1

これは基本的にあなたが使い始めたコードと同じです。あなたはそこに「待って」いる必要があります... – Servy

+0

@セイビィ:今私は混乱しています:それはあなたの上にコメントしたことはありませんタスク。結果もブロックできますか?コードは途中で動作します:4タスクで10タスク、各タスクは3秒間スリープします。 – Andomar

+2

async/awaitの使用のポイントは、(このコードが座っている)メソッド全体がブロックされないということです。メソッドは、GUIアプリケーションのイベントなどから呼び出すことができ、UIスレッドをブロックすることはできません(UIスレッドで必要なコードをすべて実行しながら)。 'await'を使うと、メソッドは実際に結果を返さず、結果がいつ計算されたのか(場合によってはそれらの結果が何であるか)を通知するタスクを返します。 – Servy

関連する問題