asynchronousTask.WhenAll超时
有没有在新的asynchronousdotnet 4.5库的方式来设置Task.WhenAll
方法的超时。 我想获取几个来源,并在5秒后停止,并跳过未完成的来源。
您可以使用Task.WhenAny()
将生成的Task
与Task.Delay()
使用:
await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(timeout));
如果你想在超时的情况下收获完成的任务:
var completedResults = tasks .Where(t => t.Status == TaskStatus.RanToCompletion) .Select(t => t.Result) .ToList();
我认为一个更清晰,更强大的选项,也是exception处理的权利将是使用Task.WhenAny
每个任务连同一个超时任务 ,通过所有完成的任务,并过滤超时的任务,并使用await Task.WhenAll()
而不是Task.Result
来收集所有的结果。
这是一个完整的工作解决scheme:
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); }
查看微软基于任务的asynchronous模式概述中的“Early Bailout”和“Task.Delay”部分。
提前救市。 由t1表示的操作可以在另一个任务t2中分组为WhenAny,并且我们可以等待WhenAny任务。 t2可能代表一个超时或取消,或其他一些信号,这会导致在完成t1之前的任何任务。
你所描述的似乎是一个非常普遍的需求,但是我找不到任何一个这样的例子。 我搜查了很多…我最终创build了以下内容:
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();
我在这里假设一个返回Task <MyResult>的方法SomeTaskAsync。
从已完成的任务的成员中,只有types为MyResult的任务是我们自己的任务,设法打败了时钟。 Task.Delay返回一个不同的types。 这需要打字方面的一些妥协,但仍然工作美观,相当简单。
(当然可以使用查询+ ToArraydynamic构build数组)。
- 请注意,此实现不需要SomeTaskAsync来接收取消令牌。
我来到下面这段代码,做我所需要的:
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<Task<List<MyObject>>> listoftasks = new List<Task<List<MyObject>>>(); listoftasks.Add(GetGoogle(cts)); listoftasks.Add(GetTwitter(cts)); listoftasks.Add(GetSleep(cts)); listoftasks.Add(GetxSleep(cts)); List<MyObject>[] arrayofanswers = Task.WhenAll(listoftasks).Result; List<MyObject> answer = new List<MyObject>(); foreach (List<MyObject> answers in arrayofanswers) { answer.AddRange(answers); } foreach (MyObject o in answer) { Console.WriteLine("{0} - {1}", o.name, o.origin); } Console.WriteLine("Press <Enter>"); Console.ReadLine(); } static async Task<List<MyObject>> GetGoogle(CancellationTokenSource cts) { try { Console.WriteLine("Start GetGoogle"); List<MyObject> l = new List<MyObject>(); var client = new HttpClient(); Task<HttpResponseMessage> 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<MyObject>(); } } static async Task<List<MyObject>> GetTwitter(CancellationTokenSource cts) { try { Console.WriteLine("Start GetTwitter"); List<MyObject> l = new List<MyObject>(); var client = new HttpClient(); Task<HttpResponseMessage> 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<MyObject>(); } } static async Task<List<MyObject>> GetSleep(CancellationTokenSource cts) { try { Console.WriteLine("Start GetSleep"); List<MyObject> l = new List<MyObject>(); await Task.Delay(5000,cts.Token); l.Add(new MyObject() { name = "Slept well", origin = "sleep" }); return l; } catch (TaskCanceledException) { return new List<MyObject>(); } } static async Task<List<MyObject>> GetxSleep(CancellationTokenSource cts) { Console.WriteLine("Start GetxSleep"); List<MyObject> l = new List<MyObject>(); await Task.Delay(2000); cts.Cancel(); l.Add(new MyObject() { name = "Slept short", origin = "xsleep" }); return l; } } }
我的解释是在我的博文中: http : //blog.bekijkhet.com/2012/03/c-async-examples-whenall-whenany.html
查看http://tutorials.csharp-online.net/Task_Combinators中提出的自定义任务组合器;
async static Task<TResult> WithTimeout<TResult> (this Task<TResult> 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 }
我还没有尝试过。
除了svick的回答之外,当我需要等待几个任务完成,但是在等待的时候还得处理其他的东西的时候,下面的例子对我有用:
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 }
除了超时之外,如果您正在构build一个Web应用程序,我还会检查这个有用的取消。
public static async Task WhenAll( IEnumerable<Task> 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(); } } }
看起来像Task.WaitAll重载与超时参数是你所需要的 – 如果它返回true,那么你知道他们都完成了 – 否则,你可以过滤IsCompleted。
if (Task.WaitAll(tasks, myTimeout) == false) { tasks = tasks.Where(t => t.IsCompleted); } ...