[英]How to - Multiple Async tasks with timeout and cancellation
我想在設置超時時觸發幾項任務。 我們的想法是從擊敗時鍾的任務中收集結果,並取消(甚至忽略)其他任務。
我嘗試使用擴展方法WithCancellation作為解釋這里 ,但是拋出一個異常造成WhenAll返回和供應沒有結果。
這是我嘗試過的,但我也向其他方向開放(注意我需要使用await而不是Task.Run,因為我需要在Tasks中使用httpContext):
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
IEnumerable<Task<MyResults>> tasks =
from url in urls
select taskAsync(url).WithCancellation(cts.Token);
Task<MyResults>[] excutedTasks = null;
MyResults[] res = null;
try
{
// Execute the query and start the searches:
excutedTasks = tasks.ToArray();
res = await Task.WhenAll(excutedTasks);
}
catch (Exception exc)
{
if (excutedTasks != null)
{
foreach (Task<MyResults> faulted in excutedTasks.Where(t => t.IsFaulted))
{
// work with faulted and faulted.Exception
}
}
}
// work with res
編輯:關注 @ Servy的答案,這是我實施的實施:
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
IEnumerable<Task<MyResults>> tasks =
from url in urls
select taskAsync(url).WithCancellation(cts.Token);
// Execute the query and start the searches:
Task<MyResults>[] excutedTasks = tasks.ToArray();
try
{
await Task.WhenAll(excutedTasks);
}
catch (OperationCanceledException)
{
// Do nothing - we expect this if a timeout has occurred
}
IEnumerable<Task<MyResults>> completedTasks = excutedTasks.Where(t => t.Status == TaskStatus.RanToCompletion);
var results = new List<MyResults>();
completedTasks.ForEach(async t => results.Add(await t));
如果有任何的任務無法完成,你是正確的, WhenAll
不返回任何沒有完成的結果,它只是包裝的所有故障的集合例外。 幸運的是,您擁有原始的任務集合,因此您可以從那里獲得成功完成的結果。
var completedTasks = excutedTasks.Where(t => t.Status == TaskStatus.RanToCompletion);
只需使用它而不是res
。
我嘗試了你的代碼並且它運行得很好,除了取消的任務不處於Faulted狀態,而是處於Cancelled狀態。 因此,如果您想要處理已取消的任務,請使用t.IsCanceled
。 未取消的任務已完成。 這是我使用的代碼:
public static async Task MainAsync()
{
var urls = new List<string> {"url1", "url2", "url3", "url4", "url5", "url6"};
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
IEnumerable<Task<MyResults>> tasks =
from url in urls
select taskAsync(url).WithCancellation(cts.Token);
Task<MyResults>[] excutedTasks = null;
MyResults[] res = null;
try
{
// Execute the query and start the searches:
excutedTasks = tasks.ToArray();
res = await Task.WhenAll(excutedTasks);
}
catch (Exception exc)
{
if (excutedTasks != null)
{
foreach (Task<MyResults> faulted in excutedTasks.Where(t => t.IsFaulted))
{
// work with faulted and faulted.Exception
}
}
}
}
public static async Task<MyResults> taskAsync(string url)
{
Console.WriteLine("Start " + url);
var random = new Random();
var delay = random.Next(10);
await Task.Delay(TimeSpan.FromSeconds(delay));
Console.WriteLine("End " + url);
return new MyResults();
}
private static void Main(string[] args)
{
MainAsync().Wait();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.