Task.WhenAll
用于等待所有提供的Task对象完成执行。这个方法返回一个新的Task,这个Task将在所有提供的Task完成后完成。如果任何一个Task失败,Task.WhenAll
返回的Task也将以异常状态完成。这个方法非常适合在你需要并行执行多个操作,并且需要等待所有操作完成后才能继续执行的情况。例如,你可能需要从多个源并行下载数据,然后在所有下载完成后处理这些数据。使用Task.WhenAll
可以使你的代码更简洁,更易于理解和维护。你不需要手动跟踪每个Task的状态,也不需要编写复杂的代码来处理并行操作的结果。
如图我在文件夹中创建了三个记事本
然后我们创建三个异步任务t1、t2和t3,分别异步读取三个不同的文件。使用Task.WhenAll方法等待这三个任务全部完成。
class MyClass
{
public static async Task Main(string[] args)
{
var t1 = File.ReadAllTextAsync(@"G:\txt\txt1.txt");
var t2 = File.ReadAllTextAsync(@"G:\txt\txt2.txt");
var t3 = File.ReadAllTextAsync(@"G:\txt\txt3.txt");
string[] strings = await Task.WhenAll(t1, t2, t3);
Console.WriteLine( strings[0]);
Console.WriteLine( strings[1]);
Console.WriteLine( strings[2]);
}
}
在断点中也可以看出,await Task.WhenAll(t1, t2, t3)会等待t1、t2和t3都完成,然后继续执行后面的代码。
阻塞与非阻塞:WaitAll
是一个阻塞方法,意味着它会阻塞当前的线程直到所有的任务都完成。而WhenAll
是一个非阻塞方法,它会立即返回一个Task
,这个Task
在所有的任务都完成时完成。
异常处理:如果多个任务中有一个或多个抛出异常,WaitAll
会抛出一个AggregateException
,这个异常包含所有的异常。而WhenAll
返回的Task
在完成时如果有异常会抛出一个AggregateException
。
使用场景:WaitAll
通常用于控制台应用程序或者需要阻塞当前线程等待所有任务完成的场景。WhenAll
通常用于UI或ASP.NET应用程序,这些应用程序需要避免阻塞当前线程,并允许其他工作在等待所有任务完成时继续进行。
返回值:WaitAll
没有返回值,而WhenAll
返回一个Task
,可以通过这个Task
获取所有任务的结果。
避免在UI线程上使用Task.WaitAll,因为这会阻塞UI线程,导致应用程序无响应。如果你需要在UI线程上等待多个任务完成,应使用await Task.WhenAll。
Task.WaitAll和Task.WhenAll都会抛出AggregateException,如果任何等待的任务抛出未处理的异常。你需要处理这个异常,或者确保所有任务都正确处理了它们的异常。
Task.WhenAll返回一个任务,这个任务在所有给定的任务完成时完成。这意味着,如果你不等待或异步等待这个任务,你可能会在所有任务完成之前继续执行。如果你需要等待所有任务完成,你应该使用await关键字或者Result属性。
Task.WaitAll和Task.WhenAll都不会取消等待的任务。如果你需要取消任务,你应该使用CancellationToken。
如果你使用Task.WhenAll,你应该注意,即使一个任务失败,其他任务仍然会继续执行。如果你需要在一个任务失败时取消所有任务,你需要使用CancellationTokenSource并在一个任务失败时调用Cancel方法。
Task.WaitAll和Task.WhenAll都不会处理任务的结果。如果你需要处理任务的结果,你应该在任务完成后处理结果,或者使用Task.WhenAll返回的任务的Result属性。