繁体   English   中英

如何 - 具有超时和取消的多个异步任务

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM