2016-09-21 22 views
5

yılında tamamlandığında için bir geri arama var mı.bir görev aşağıdaki Ben olduğunu varsayalım Task.WhenAll

Her bir sonucu işlemek için bir yol var mı talep üzerine?

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

Belki 'görevleri [i] .ContinueWith()'? –

cevap

4

talep üzerine her sonucu işlemek için bir yolu var mı: Bir görev tamamlandığında yürütülen alacak bir temsilci/geri arama kayıt gibi

?

Evet, bunun yerine WhenAll ait WhenAny kullanın ... ya da her göreve ContinueWith arayın. WhenAny yaklaşım için Örneğin

: Orada sırayla tamamlar görevlerin bir dizinin içine görevlerin orijinal dizisini dönüşümü Kullanabileceğin başka bir seçenek, ama

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

aynı sonuçları veren. Detaylar this blog post içindedir fakat sonuç kullanabilirsiniz olmasıdır:

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

Teşekkür ederiz!Ben daha temiz ve daha doğru olarak göründüğü gibi 'ContinueWith 'yaklaşımı ile gideceğim düşünüyorum –

+0

@JonSkeet Bize bir üne kazanalım :) –

+0

@MatiasCicero: Her ikisi de semantik olarak doğrudur - sadece sonuçta ne olduğuna bağlı En basit. Başka bir alternatife bağlantı ekleniyor ... –

4

talep üzerine her sonucu işlemek için bir yolu var mı? Bir görev

Evet

tamamlandığında yürütülen alacak bir temsilci/geri arama kayıt gibi

, sadece senin biraz düşünme ayarlamak zorunda.

Geri aramaları kaydetmeyi unut (ContinueWith is a dangerous, extremely low-level API). Ayrıca, neredeyse tamamlanmadıkça görevleri sipariş etmek zorunda kalmazsınız. Bunun yerine, sorununuzu işlemleri (görevler) açısından düşünün.

Şu anda TimeSpan döndüren bir dizi görev var. Bu koleksiyondaki her öğe TimeSpan döndüren tek bir işlemdir. Gerçekten yapmak istediğiniz şey, orijinal işlemin tamamlanmasını bekledikten sonra işlem sonrası mantığınızı yürüten bir üst düzey işlemin konseptini sunmaktır.

Bu async/ await için tam olarak ne olduğunu

:

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) 
} 

Şimdi, mevcut operasyonlara bu üst düzey operasyonu uygulamak istiyoruz. LINQ en Select bunun için idealdir: Sonuçlardan son koleksiyonunu gerekmiyorsa

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. 

, bu daha da basitleştirilmiş olabilir:

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

Gerçekten * LINQ en 'Select' kullanımınız tarafından * hayret değilim. Bu sadece mükemmel! –

İlgili konular