2016-09-21 9 views
5

に完了したときのコールバックがあります。タスクは、以下の私が持っていると仮定しTask.WhenAll

各結果を処理する方法はありますかオンデマンドで

IEnumerable<Task<TimeSpan>> tasks = //... 
await Task.WhenAll(tasks, result => 
{ 
    // A task has finished. This will get executed. 
    // result is of type TimeSpan 
}); 
+1

たぶん 'タスク[i]を.ContinueWith()'? –

答えて

4

オンデマンドでそれぞれの結果を処理する方法はあります:タスクが完了したときに実行されますデリゲート/コールバックを登録するよう

はい、あなたの代わりにWhenAllWhenAny使用...または各タスクにContinueWithを呼び出します。例えば

は、WhenAnyアプローチのために:

ISet<Task<TimeSpan>> tasks = new HashSet<Task<TimeSpan>>(...); 
while (tasks.Count != 0) 
{ 
    var task = await Task.WhenAny(tasks); 
    // Use task here 
    tasks.Remove(task); 
} 

ありますが順番に完了したタスクのシーケンスにタスクの元のシーケンスを変換するあなたが使用できる別のオプションは、ですが、同じ結果を与えます。詳細はthis blog postであるが、結果はあなたが使用できるということです。

foreach (var task in tasks.InCompletionOrder()) 
{ 
    var result = await task; 
    // Use the result 
} 
+0

ありがとう! –

+0

@JonSkeet最も単純です。他の選択肢へのリンクを追加する... –

+0

@MatiasCicero:両方とも意味的に正しいです - それはちょうど何が終わるかに依存しています。私は私が 'ContinueWith'アプローチで行くと思っています。より洗練されてより意味的に正しいと思われます。 –

4

オンデマンドでそれぞれの結果を処理する方法はありますか?

タスクが

を完了したときに実行されますデリゲート/コールバックを登録するようはい、あなたは自分の思考ビットを調整する必要があります。

コールバックの登録を忘れる(ContinueWith is a dangerous, extremely low-level API)。また、完了までにタスクを注文する必要はほとんどありません。代わりに、操作(タスク)の点で問題を考えてください。

今のところ、TimeSpanを返す一連のタスクがあります。そのコレクション内の各アイテムは、TimeSpanを返す単一の操作です。あなたが本当にやりたいことは、元の操作が完了するのを待ってから、操作後のロジックを実行する、単一の高レベルの操作という概念を導入することです。

これがために、まさにasync/awaitです:

private static async Task<TimeSpan> HandleResultAsync(Task<TimeSpan> operation) 
{ 
    var result = await operation; 
    // A task has finished. This will get executed. 
    // result is of type TimeSpan 
    ... 
    return result; // (assuming you want to propagate the result) 
} 

、既存のオペレーションにこの高レベルの操作を適用したいです。 LINQのSelectは、このために最適です:

IEnumerable<Task<TimeSpan>> tasks = ... 
IEnumerable<Task<TimeSpan>> higherLevelTasks = tasks.Select(HandleResultAsync); 

TimeSpan[] results = await Task.WhenAll(higherLevelTasks); 
// By the time you get here, all results have been handled individually. 

あなたは結果の最後のコレクションを必要としない場合は、これをさらに簡略化することができます。

private static async Task HandleResultAsync(Task<TimeSpan> operation) 
{ 
    var result = await operation; 
    // A task has finished. This will get executed. 
    // result is of type TimeSpan 
    ... 
} 

IEnumerable<Task<TimeSpan>> tasks = ... 
IEnumerable<Task> higherLevelTasks = tasks.Select(HandleResultAsync); 
await Task.WhenAll(higherLevelTasks); 
+0

私はあなたのLINQの「選択」の使用によって本当に驚いています。それは完璧です! –

関連する問題