Tarea asincrónica. Cuando todo con tiempo de espera

¿Hay alguna manera en la nueva biblioteca async dotnet 4.5 para establecer un tiempo de espera en el método Task.WhenAll . Quiero buscar varias fonts y parar después de decir 5 segundos y omitir las fonts que no fueron terminadas.

Puede combinar la Task resultante con una Task.Delay() usando Task.WhenAny() :

 await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(timeout)); 

Si desea cosechar tareas completadas en caso de un tiempo de espera:

 var completedResults = tasks .Where(t => t.Status == TaskStatus.RanToCompletion) .Select(t => t.Result) .ToList(); 

Creo que una opción más clara y más robusta que también maneje la excepción sería utilizar Task.WhenAny en cada tarea junto con una tarea de tiempo de espera , pasar por todas las tareas completadas y filtrar los await Task.WhenAll() y usar await Task.WhenAll() lugar de Task.Result para recostackr todos los resultados.

Aquí hay una solución de trabajo completa:

 static async Task WhenAll(IEnumerable> 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); } 

Consulte las secciones “Rescatar anticipadamente” y “Tarea.Retirar” de la Descripción general del patrón asíncrono basado en tareas de Microsoft.

Rescate anticipado Una operación representada por t1 se puede agrupar en WhenAny con otra tarea t2, y podemos esperar en la tarea WhenAny. t2 podría representar un tiempo de espera, o cancelación, o alguna otra señal que provocará que la tarea WhenAny se complete antes de completar t1.

Lo que describes parece ser una demanda muy común, sin embargo, no pude encontrar en ningún lado un ejemplo de esto. Y busqué mucho … finalmente creé lo siguiente:

 TimeSpan timeout = TimeSpan.FromSeconds(5.0); 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 = completedTasks.OfType>().Select(task => task.Result).ToList(); 

Supongo que aquí un método SomeTaskAsync que devuelve la tarea .

De los miembros de CompletedTasks, solo las tareas de tipo MyResult son nuestras propias tareas que lograron ganarle al reloj. Task.Delay devuelve un tipo diferente. Esto requiere cierto compromiso al escribir, pero aún funciona de manera hermosa y bastante simple.

(Por supuesto, la matriz se puede construir dinámicamente usando una consulta + ToArray).

  • Tenga en cuenta que esta implementación no requiere SomeTaskAsync para recibir un token de cancelación.

Además del tiempo de espera, también verifico la cancelación que es útil si estás construyendo una aplicación web.

 public static async Task WhenAll( IEnumerable tasks, int millisecondsTimeOut, CancellationToken cancellationToken) { using(Task timeoutTask = Task.Delay(millisecondsTimeOut)) using(Task cancellationMonitorTask = Task.Delay(-1, cancellationToken)) { Task completedTask = await Task.WhenAny( Task.WhenAll(tasks), timeoutTask, cancellationMonitorTask ); if (completedTask == timeoutTask) { throw new TimeoutException(); } if (completedTask == cancellationMonitorTask) { throw new OperationCanceledException(); } await completedTask; } } 

Llegué al siguiente código que hace lo que necesitaba:

 using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Net.Http; using System.Json; using System.Threading; namespace MyAsync { class Program { static void Main(string[] args) { var cts = new CancellationTokenSource(); Console.WriteLine("Start Main"); List>> listoftasks = new List>>(); listoftasks.Add(GetGoogle(cts)); listoftasks.Add(GetTwitter(cts)); listoftasks.Add(GetSleep(cts)); listoftasks.Add(GetxSleep(cts)); List[] arrayofanswers = Task.WhenAll(listoftasks).Result; List answer = new List(); foreach (List answers in arrayofanswers) { answer.AddRange(answers); } foreach (MyObject o in answer) { Console.WriteLine("{0} - {1}", o.name, o.origin); } Console.WriteLine("Press "); Console.ReadLine(); } static async Task> GetGoogle(CancellationTokenSource cts) { try { Console.WriteLine("Start GetGoogle"); List l = new List(); var client = new HttpClient(); Task awaitable = client.GetAsync("http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=broersa", cts.Token); HttpResponseMessage res = await awaitable; Console.WriteLine("After GetGoogle GetAsync"); dynamic data = JsonValue.Parse(res.Content.ReadAsStringAsync().Result); Console.WriteLine("After GetGoogle ReadAsStringAsync"); foreach (var r in data.responseData.results) { l.Add(new MyObject() { name = r.titleNoFormatting, origin = "google" }); } return l; } catch (TaskCanceledException) { return new List(); } } static async Task> GetTwitter(CancellationTokenSource cts) { try { Console.WriteLine("Start GetTwitter"); List l = new List(); var client = new HttpClient(); Task awaitable = client.GetAsync("http://search.twitter.com/search.json?q=broersa&rpp=5&include_entities=true&result_type=mixed",cts.Token); HttpResponseMessage res = await awaitable; Console.WriteLine("After GetTwitter GetAsync"); dynamic data = JsonValue.Parse(res.Content.ReadAsStringAsync().Result); Console.WriteLine("After GetTwitter ReadAsStringAsync"); foreach (var r in data.results) { l.Add(new MyObject() { name = r.text, origin = "twitter" }); } return l; } catch (TaskCanceledException) { return new List(); } } static async Task> GetSleep(CancellationTokenSource cts) { try { Console.WriteLine("Start GetSleep"); List l = new List(); await Task.Delay(5000,cts.Token); l.Add(new MyObject() { name = "Slept well", origin = "sleep" }); return l; } catch (TaskCanceledException) { return new List(); } } static async Task> GetxSleep(CancellationTokenSource cts) { Console.WriteLine("Start GetxSleep"); List l = new List(); await Task.Delay(2000); cts.Cancel(); l.Add(new MyObject() { name = "Slept short", origin = "xsleep" }); return l; } } } 

Mi explicación está en mi blogpost: http://blog.bekijkhet.com/2012/03/c-async-examples-whenall-whenany.html

Consulte un combinador de tareas personalizado propuesto en http://tutorials.csharp-online.net/Task_Combinators

 async static Task WithTimeout (this Task task, TimeSpan timeout) { Task winner = await (Task.WhenAny (task, Task.Delay (timeout))); if (winner != task) throw new TimeoutException(); return await task; // Unwrap result/re-throw } 

Aun no lo he intentado.

Además de la respuesta de svick, lo siguiente me funciona cuando tengo que esperar a que se completen un par de tareas, pero tengo que procesar algo más mientras estoy esperando:

 Task[] TasksToWaitFor = //Your tasks TimeSpan Timeout = TimeSpan.FromSeconds( 30 ); while( true ) { await Task.WhenAny( Task.WhenAll( TasksToWaitFor ), Task.Delay( Timeout ) ); if( TasksToWaitFor.All( a => a.IsCompleted ) ) break; //Do something else here } 

Parece que la Tarea. Espera Toda la sobrecarga con el parámetro de tiempo de espera es todo lo que necesitas: si devuelve verdadero, entonces sabes que todos se completaron; de lo contrario, puedes filtrar por IsCompleted.

 if (Task.WaitAll(tasks, myTimeout) == false) { tasks = tasks.Where(t => t.IsCompleted); } ...