如何 - 多个异步任务,暂停和取消 [英] How to - Multiple Async tasks with timeout and cancellation

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

问题描述

我想解雇几个任务,同时对他们设置超时。我们的想法是收集来自时钟节拍的任务的结果,并取消(或甚至只是忽略)其他任务。

我尝试使用扩展方法WithCancellation因为这里解释,但投掷造成WhenAll返回,并提供没有结果异常。

下面是我的尝试,但我开到其他方向,以及(不过请注意,我需要使用等待,而不是Task.Run因为我需要在任务的HttpContext):

  VAR CTS =新CancellationTokenSource(TimeSpan.FromSeconds(3));IEnumerable的<任务< MyResults>>任务=
            在网址URL
            选择taskAsync(URL).WithCancellation(cts.Token);任务< MyResults> [] excutedTasks = NULL;MyResults [] RES = NULL;
尝试
{
    //执行查询,并开始搜索:
    excutedTasks = tasks.ToArray();    RES =等待Task.WhenAll(excutedTasks);
}
赶上(例外EXC)
{
    如果(excutedTasks!= NULL)
    {
        的foreach(任务< MyResults>在excutedTasks.Where故障(T => t.IsFaulted))
        {
            //断陷带和faulted.Exception工作
        }
    }
}//与资源工作

编辑:
继@下面Servy的答案,这是我去实现:

  VAR CTS =新CancellationTokenSource(TimeSpan.FromSeconds(3));IEnumerable的<任务< MyResults>>任务=
            在网址URL
            选择taskAsync(URL).WithCancellation(cts.Token);//执行查询,并开始搜索:
任务< MyResults> [] = excutedTasks tasks.ToArray();尝试
{
    等待Task.WhenAll(excutedTasks);
}
    赶上(OperationCanceledException)
{
    //什么都不做 - 我们预计,如果发生了超时
}IEnumerable的<任务< MyResults>> completedTasks = excutedTasks.Where(T => t.Status == TaskStatus.RanToCompletion);VAR的结果=新的List< MyResults>();
completedTasks.ForEach(异步T => results.Add(等待T));


如果任何任务无法完成,你是正确的, WhenAll 不返回的结果任何确实的完整的,它只是包装的所有故障的集合例外。幸运的是,你有任务的原始集合,这样你就可以得到顺利完成,结果从那里。

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

就用这个来代替 RES

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.

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

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

EDIT: 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));

解决方案

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);

Just use that instead of res.

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

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