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

如何基于Boost.Asio的awaitable实现whenAll等任务原语

Boost.Asio awaitable<T> 协程任务原语实现方案

官方原生支持(推荐优先使用)

Boost.Asio 从1.80版本开始已经在实验性命名空间下提供了和.NET Task.WhenAll/Task.WhenAny完全对应的能力,不需要从零手写实现:

  • 头文件引入:只需要包含boost/asio/experimental/awaitable_operators.hpp即可使用所有相关原语
  • when_all(等待所有任务完成):
    支持两种调用方式,一种是通过重载的&&运算符拼接多个awaitable,另一种是直接调用可变参数模板函数when_all。传入的所有任务会自动被投递到当前协程绑定的io_context执行器上并行调度,所有任务完成后会返回包含所有任务返回值的元组,任务抛出的异常会直接向外传播。
    示例代码:
    #include <boost/asio/experimental/awaitable_operators.hpp>
    using namespace boost::asio::experimental::awaitable_operators;
    
    asio::awaitable<int> task1();
    asio::awaitable<std::string> task2();
    
    asio::awaitable<void> demo_when_all() {
      // 运算符写法
      auto [num_ret, str_ret] = co_await (task1() && task2());
      // 函数写法,支持任意数量任务
      // auto all_results = co_await when_all(task1(), task2(), task3());
    }
    
  • when_any(等待任意任务完成):
    对应提供了重载的||运算符和when_any函数,只要传入的任意一个awaitable执行完成,就会立刻恢复外层协程,剩余未完成的任务会收到取消信号自动终止。返回值是std::variant类型,按顺序存储所有可能的任务返回值类型,可以通过std::holds_alternative、std::get判断和获取第一个完成的任务结果。
    示例代码:
    asio::awaitable<void> demo_when_any() {
      asio::steady_timer timeout(co_await asio::this_coro::executor, std::chrono::seconds(3));
      auto ret = co_await (timeout.async_wait(asio::use_awaitable) || task1());
      if (std::holds_alternative<int>(ret)) {
        // task1先完成
      } else {
        // 超时先触发
      }
    }
    
  • taskFromResult/TaskCompletionSource对应能力:
    直接返回已就绪结果的taskFromResult可以用asio::make_awaitable实现,传入执行器和要返回的值,就能得到一个立即就绪的awaitable<T>。
    对应TaskCompletionSource的手动完成触发能力,可以通过自定义异步操作配合async_result实现,简单场景下用一个关联了执行器的promise即可,支持手动设置返回值、异常,触发等待的协程恢复。

旧版本Asio手动实现要点

如果使用1.80之前的Asio版本,没有内置上述原语,可以按以下逻辑自行实现:

  • 并行调度的核心是不要在同一个协程内顺序co_await多个任务(这种写法是串行执行),要把所有需要并行的任务通过asio::co_spawn投递到同一个io_context执行器上,由事件循环统一调度才能实现并行。
  • when_all实现:用原子变量维护剩余未完成任务的计数,预先分配好结果存储的内存,每个任务完成时把结果存入对应位置、计数减1,计数归0时恢复外层等待协程;如果需要异常快速失败逻辑,任意任务抛出异常时直接触发外层协程恢复,同时给其他未完成任务发送取消信号。
  • when_any实现:用原子标记位记录是否已有任务完成,任意任务完成时先通过标记位做去重检查,第一个完成的任务负责保存结果、恢复外层协程,其余任务后续完成时直接丢弃结果即可,触发恢复的同时要给所有未完成任务传递停止信号,避免资源泄漏。
  • 注意所有协程的恢复操作必须投递到对应io_context的执行器上执行,禁止跨线程直接resume协程,否则会触发数据竞争。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 22:09:49