You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何等待嵌套Task执行完成?

解决DoWork任务全部完成后再输出"Hello World!"的问题

这个问题我之前也碰到过,核心是你当前的代码没真正等待DoWork里的三个异步任务完成,就触发了后续的ContinueWith逻辑。咱们一步步来改:

为什么原来的代码会提前输出?

原来的DoWork是void类型,当你用Task.Run(() => DoWork())时,这个外层Task只会等待DoWork方法执行完毕(也就是启动三个HeavyOperation任务的代码跑完),而不会等待那三个后台任务真正完成。所以ContinueWith会立刻触发,输出"Hello World!",但三个Heavy任务还在后台跑。

修改方案

第一步:让DoWork能跟踪子任务的完成状态

把DoWork改成async Task方法,这样它能返回一个Task,用来标记所有子任务的完成状态:

public async Task DoWork() 
{ 
    // 启动三个任务,保存它们的引用
    var task1 = Task.Run(() => HeavyOperation()); 
    var task2 = Task.Run(() => HeavyOperation2()); 
    var task3 = Task.Run(() => HeavyOperation3()); 

    // 等待这三个任务全部完成
    await Task.WhenAll(task1, task2, task3);
}

这里用Task.WhenAll来等待所有子任务完成,只有当三个Heavy任务都结束后,DoWork返回的Task才会标记为完成。

第二步:让外层Task等待DoWork完成

修改Foo方法里的逻辑,现在DoWork返回Task了,外层的Task.Run会等待DoWork的Task完成(也就是所有子任务完成),再触发ContinueWith:

public void Foo() 
{ 
    Task.Run(async () => await DoWork()) 
        .ContinueWith((prev) => { 
            Console.WriteLine("Hello World!"); 
        }); 
}

或者更简洁一点,因为DoWork本身就是异步方法,直接传进去就行:

public void Foo() 
{ 
    DoWork()
        .ContinueWith((prev) => { 
            Console.WriteLine("Hello World!"); 
        }); 
}

更优雅的写法:用await代替ContinueWith

如果允许把Foo改成async方法,用await会比ContinueWith更直观,也能避免一些上下文同步的坑:

public async Task Foo() 
{ 
    await DoWork();
    Console.WriteLine("Hello World!"); 
}

这种写法代码更清晰,可读性更强,推荐在能使用async/await的场景下优先用它。

注意点

  • 不要用async void(除非是事件处理程序),因为async void无法被跟踪,也很难处理异常,这里DoWork用async Task是正确的选择。
  • Task.WhenAll会等待所有传入的Task完成,不管它们是成功还是失败,如果需要处理异常,可以在await之后或者用try/catch包裹。

内容的提问来源于stack exchange,提问作者utop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:48:38