如何 - 具有超时和取消的多个异步任务 [英] How to - Multiple Async tasks with timeout and cancellation

查看:24
本文介绍了如何 - 具有超时和取消的多个异步任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在设置超时的同时触发几个任务.我们的想法是从时钟节拍的任务中收集结果,并取消(甚至只是忽略)其他任务.

I would like to fire several tasks while setting a timeout on them. The idea is to gather the results from the tasks that beat the clock, and cancel (or even just ignore) the other tasks.

我尝试使用扩展方法 WithCancellation,如此处所述,但是抛出异常导致 WhenAll 返回并且不提供任何结果.

I tried using extension methods WithCancellation as explained here, however throwing an exception caused WhenAll to return and supply no results.

这是我尝试过的,但我也向其他方向开放(但请注意,我需要使用 await 而不是 Task.Run,​​因为我需要任务中的 httpContext):

Here's what I tried, but I'm opened to other directions as well (note however that I need to use await rather than Task.Run since I need the httpContext in the Tasks):

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 的回答,这是我采用的实现:

Following @Servy's answer below, this is the implementation I went with:

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 不会返回任何所做的结果 完成,它只是包装了所有失败的聚合异常.幸运的是,您拥有原始任务集合,因此您可以从那里获得成功完成的结果.

If any of the tasks fail to complete you are correct that WhenAll doesn't return the results of any that did complete, it just wraps an aggregate exception of all of the failures. Fortunately, you have the original collection of tasks, so you can get the results that completed successfully from there.

var completedTasks = excutedTasks.Where(t => t.Status == TaskStatus.RanToCompletion);

用那个代替 res.

这篇关于如何 - 具有超时和取消的多个异步任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆