67 votes

Async Task.WhenAll avec délai d'arrêt

Y at-il un moyen dans la nouvelle bibliothèque async dotnet 4.5 pour définir un délai d'arrêt sur la `` méthode. Je veux aller chercher plusieurs sources et arrêter après dire 5 secondes et sauter les sources qui n'étaient pas terminées.

114voto

svick Points 81772

Vous pouvez combiner le résultat avec une utilisation `` :

Si vous souhaitez récolter les tâches terminées en cas de délai d'attente :

27voto

I3arnon Points 9498

Je pense plus clair, plus robuste option qui a également fait la gestion des exceptions droit serait d'utiliser Task.WhenAny sur chaque tâche en collaboration avec un délai d'attente de tâche, passer par toutes les tâches et filtrer le délai d'attente et await Task.WhenAll() au lieu de Task.Result pour rassembler tous les résultats.

Voici une complète solution de travail:

static async Task<TResult[]> WhenAll<TResult>(IEnumerable<Task<TResult>> tasks, TimeSpan timeout)
{
    var timeoutTask = Task.Delay(timeout).ContinueWith(_ => default(TResult));
    var completedTasks = 
        (await Task.WhenAll(tasks.Select(task => Task.WhenAny(task, timeoutTask)))).
        Where(task => task != timeoutTask);
    return await Task.WhenAll(completedTasks);
}

9voto

David Peden Points 3532

Consultez les sections « Early Bailout » et « Task.Delay » de microsoft's Task-Based Asynchronous Pattern Overview.

  • Sauvetage anticipé. Une opération représentée par t1 peut être regroupée dans un WhenAny avec une autre tâche t2, et nous pouvons attendre sur la tâche WhenAny. t2 pourrait représenter un délai d'arrêt, ou une annulation, ou un autre signal qui entraînera la tâche WhenAny à terminer avant t1 terminé.

2voto

Erez Cohen Points 190

Ce que vous décrivez semble être un très commun de la demande cependant je ne pouvais pas trouver n'importe où, un exemple de cela. Et j'ai beaucoup cherché... j'ai finalement créé le suivant:

TimeSpan timeout = TimeSpan.FromSeconds(5.0);

Task<Task>[] tasksOfTasks =
{
    Task.WhenAny(SomeTaskAsync("a"), Task.Delay(timeout)),
    Task.WhenAny(SomeTaskAsync("b"), Task.Delay(timeout)),
    Task.WhenAny(SomeTaskAsync("c"), Task.Delay(timeout))
};

Task[] completedTasks = await Task.WhenAll(tasksOfTasks);

List<MyResult> = completedTasks.OfType<Task<MyResult>>().Select(task => task.Result).ToList();

Je suppose ici une méthode SomeTaskAsync que revient la Tâche<MyResult>.

Parmi les membres de completedTasks, seules les tâches de type MyResult sont nos propres tâches qui ont réussi à battre l'horloge. De la tâche.Retard retourne un type différent. Cela nécessite de faire des compromis sur le typage, mais tout fonctionne à merveille et très simple.

(Le tableau peut bien sûr être construit de manière dynamique à l'aide d'une requête + ToArray).

  • Notez que cette mise en œuvre ne nécessite pas de SomeTaskAsync de recevoir un jeton d'annulation.

0voto

broersa Points 446

Je suis venu à la pièce suivante de code qui fait ce dont j'avais besoin:

Mon explication est dans mon blogpost: http://blog.bekijkhet.com/2012/03/c-async-examples-whenall-whenany.html

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X