Task.WhenAll()和foreach(任务中的var任务)之间有什么区别? [英] What's the diference between Task.WhenAll() and foreach(var task in tasks)

查看:105
本文介绍了Task.WhenAll()和foreach(任务中的var任务)之间有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

经过数小时的努力,我发现我的应用程序中存在一个错误.我认为下面的两个函数具有相同的行为,但事实证明它们不相同.

After a few hours of struggle I found a bug in my app. I considered the 2 functions below to have identical behavior, but it turned out they don't.

谁能告诉我幕后的真实情况,以及为什么他们以不同的方式行事?

Can anyone tell me what's really going on under the hood, and why they behave in a different way?

public async Task MyFunction1(IEnumerable<Task> tasks){
    await Task.WhenAll(tasks);

    Console.WriteLine("all done"); // happens AFTER all tasks are finished
}

public async Task MyFunction2(IEnumerable<Task> tasks){
    foreach(var task in tasks){
        await task;
    }

    Console.WriteLine("all done"); // happens BEFORE all tasks are finished
}

推荐答案

如果所有任务成功完成,它们将发挥相同的作用 .

They'll function identically if all tasks complete successfully.

如果您使用WhenAll并且任何项目失败,那么直到所有项目都完成后它仍然不会完成,并且它将代表一个AggregatException,其中包装了 all 个错误所有任务.

If you use WhenAll and any items fail, it still won't be completed until all of the items are finished, and it'll represent an AggregatException that wraps all errors from all tasks.

如果您每个await个,只要它遇到任何 个失败的项目,它就会立即完成,并且表示该 one 错误的例外,没有其他人.

If you await each one then it'll complete as soon as it hits any item that fails, and it'll represent an exception for that one error, not any others.

两者之间的区别还在于,WhenAll将在开始时实现整个IEnumerable,然后再将任何延续添加到其他项目.如果IEnumerable表示已经存在并已启动的任务的集合,则这无关紧要,但是如果迭代可枚举的行为创建和/或启动任务,则在启动时具体化序列将使它们并行运行,并且在获取下一个任务之前等待它们将按顺序执行它们.下面是您可以传递的IEnumerable,其行为与我在此处描述的相同:

The two also differ in that WhenAll will materialize the entire IEnumerable right at the start, before adding any continuations to other items. If the IEnumerable represents a collection of already existing and started tasks, then this isn't relevant, but if the act of iterating the enumerable creates and/or starts tasks, then materializing the sequence at the start would run them all in parallel, and awaiting each before fetching the next task would execute them sequentially. Below is a IEnumerable you could pass in that would behave as I've described here:

public static IEnumerable<Task> TaskGeneratorSequence()
{
    for(int i = 0; i < 10; i++)
        yield return Task.Delay(TimeSpan.FromSeconds(2);
}

这篇关于Task.WhenAll()和foreach(任务中的var任务)之间有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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