等待Task.WhenAll()与Task.WhenAll().Wait()的区别

29

我有一个方法可以生成任务数组(关于线程的问题请参见我的上一篇文章),在方法结束时,我有以下选择:

await Task.WhenAll(tasks); // done in a method marked with async
Task.WhenAll(tasks).Wait(); // done in any type of method
Task.WaitAll(tasks);

基本上我想知道这两个whenall之间的区别,因为第一个似乎不会等待任务完成,而第二个会等待,但如果它不是异步的,我不想使用第二个。

我包含了第三个选项,因为我理解这将锁定当前线程直到所有任务完成处理(看起来是同步的而不是异步的)- 如果我对此错了,请纠正我。

带有await的示例函数:

public async void RunSearchAsync()
{
    _tasks = new List<Task>();
    Task<List<SearchResult>> products = SearchProductsAsync(CoreCache.AllProducts);
    Task<List<SearchResult>> brochures = SearchProductsAsync(CoreCache.AllBrochures);

    _tasks.Add(products);
    _tasks.Add(brochures);

    await Task.WhenAll(_tasks.ToArray());
    //code here hit before all _tasks completed but if I take off the async and change the above line to:

    // Task.WhenAll(_tasks.ToArray()).Wait();
    // code here hit after _tasks are completed
 }

你的意思是第二个选项不是异步的吗?你触发的任务将在不同的线程下进行处理,Wait和WaitAll会影响主线程。 - T McKeown
@TMcKeown 哦,我以为 await 的作用是等待 whenall 中的所有进程都完成后再继续执行其后的任何代码。 - Pete
4
@Pete: "await Task.WhenAll" 应该可行。确保你在 .NET 4.5 平台上,并在你的 web.config 中将 targetFramework 设置为 4.5。 - Stephen Cleary
1
@Pete:您确定在await Task.WhenAll(_tasks.Toarray())之后会执行该代码吗?我尝试了您的示例,但它会等待所有任务完成。 - dotnetstep
2个回答

32

await在等待的任务完成后会返回给调用方,并恢复方法执行。

WhenAll会创建一个任务,在所有任务都完成后才会完成。

WaitAll会阻塞创建线程(主线程),直到所有任务都完成。


因此,使用await Task.WhenAll和Tasks.WhenAll().Wait()应该没有区别,因为两者都应等待whenall中的所有任务完成(因为它将创建新任务,然后等待新任务完成),但是根据我的编辑,我发现它们之间有不同的行为,后者更像是一个WaitAll。 - Pete
@TMcKeown await Task.WhenAll(...); 应该等待 WhenAll 返回的任务,为什么你说 OP 代码中的 await 调用没有使用返回的任务?我希望能得到一个解释。 - batbrat
我认为那是不正确的。我已经删除了那个注释。 - T McKeown

0

谈论 await Task.WhenAll(tasks) vs Task.WhenAll(tasks).Wait()。如果执行处于异步上下文中,请始终避免使用 .Wait.Result,因为这些会破坏异步范式。

这两个都会阻塞线程,不允许其他操作进行。在小型应用程序中可能不是大问题,但如果您正在处理高需求服务,则会出现问题。这可能会导致线程饥饿

另一方面,await 等待后台任务完成,但不会阻塞线程,使框架/CPU可以将其用于任何其他任务。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接