C++20协程搭配asio::thread_pool未跨线程分发问题咨询
问题核心原因
串行问题由三个核心错误共同导致:
- Asio的
awaitable默认携带strand执行约束,子协程会继承父协程的strand上下文,同一strand下的协程默认强制串行执行,你没有显式为子协程绑定全局线程池执行器,所有子协程都被限制在run_all()所在的单一线程上下文中调度 - 你使用的
std::this_thread::sleep_for是同步阻塞调用,会直接占住当前运行线程,不会让出执行权给其他协程,即使有空闲线程也不会触发调度切换 &&并行等待操作符默认不会自动为子协程做执行器分发,仅会在当前上下文中按顺序启动子协程
修正方案
需要做两处核心调整:
- 用Asio内置的异步等待接口替换同步sleep,让协程在等待阶段主动挂起,让出线程资源给其他任务调度
- 给每个子协程显式绑定线程池的全局执行器,打破父协程的strand约束,确保子协程可以被分发到不同线程并行执行
修改后的参考代码
#include <asio.hpp> #include <asio/experimental/awaitable_operators.hpp> #include <chrono> #include <iostream> #include <string> using namespace std::chrono_literals; using namespace asio::experimental::awaitable_operators; asio::awaitable<std::string> one() { // 异步等待替代同步阻塞,挂起协程让出线程 co_await asio::steady_timer(co_await asio::this_coro::executor, 1s).async_wait(asio::use_awaitable); std::cout << "one run on thread: " << std::this_thread::get_id() << std::endl; co_return "egy"; } asio::awaitable<std::string> two() { co_await asio::steady_timer(co_await asio::this_coro::executor, 1s).async_wait(asio::use_awaitable); std::cout << "two run on thread: " << std::this_thread::get_id() << std::endl; co_return "ketto"; } asio::awaitable<std::string> three() { co_await asio::steady_timer(co_await asio::this_coro::executor, 1s).async_wait(asio::use_awaitable); std::cout << "three run on thread: " << std::this_thread::get_id() << std::endl; co_return "harom"; } asio::awaitable<void> run_all(asio::thread_pool& pool) { // 显式为每个子协程绑定全局线程池执行器,打破strand串行约束 auto [first, second, third] = co_await( asio::bind_executor(pool.get_executor(), one()) && asio::bind_executor(pool.get_executor(), two()) && asio::bind_executor(pool.get_executor(), three()) ); std::cout << first << " " << second << " " << third << std::endl; } int main() { asio::thread_pool pool(4); co_spawn(pool, run_all(pool), asio::detached); pool.join(); return 0; }
修改后运行总耗时约1秒,三个协程会被调度到不同线程并行执行。
内容的提问来源于stack exchange,提问作者hammurapi
相关产品推荐
相关产品推荐

