#include #include #include #include namespace asio = boost::asio; asio::awaitable calculate_value() { asio::steady_timer timer(co_await asio::this_coro::executor); timer.expires_after(std::chrono::seconds(1)); // 这里的 async_wait 是这样的: // 1. 告诉操作系统:"1秒后叫醒我" // 2. 操作系统内核开始计时 // 3. 你的线程继续做其他事 // 4. 1秒后,操作系统主动通知你的程序 // 所以这里在这 1 秒期间内,不占用任何CPU资源。 co_await timer.async_wait(asio::use_awaitable); co_return 42; /* 2025-12-16 按照我目前的理解,这个 协程和线程的底层核心 */ } asio::awaitable process_task() { try { std::cout << "开始计算...\n"; int result = co_await calculate_value(); // 等待子协程 std::cout << "计算结果: " << result << "\n"; } catch (const std::exception& e) { std::cerr << "计算错误: " << e.what() << "\n"; throw; // 重新抛出,让调用者知道 } } int test1() { asio::io_context io; // 使用 use_future 获取 future // co_spawn 只是安排协程,并无动作和运行。 std::future fut = asio::co_spawn(io, process_task(), asio::use_future); // 在工作线程中运行 io_context std::thread io_thread([&io]() { io.run(); }); std::cout << "主线程等待协程完成...\n"; try { // 等待协程完成 fut.get(); std::cout << "协程成功完成\n"; } catch (const std::exception& e) { std::cerr << "协程异常: " << e.what() << "\n"; } io_thread.join(); return 0; } // 这是一个阻塞版本的Worker class Worker { public: Worker() = default; bool Run() { isOk_ = false; if (!simulateCal()) { return false; } std::cout << "Done..." << calData_ << std::endl; return true; } private: bool simulateCal() { std::this_thread::sleep_for(std::chrono::seconds(3)); calData_ = 12; return true; } private: bool isOk_{}; int calData_{}; }; int testRun() { Worker wk; return wk.Run(); } // 上面阻塞版本的Worker改成协程版本 class WorkerCoroutine { public: WorkerCoroutine(asio::io_context& io) : io_(io), pool_(std::thread::hardware_concurrency()) { } asio::awaitable Run() { isOk_ = false; bool success = co_await simulateCal(); if (!success) { co_return false; } std::cout << "Done..." << calData_ << std::endl; isOk_ = true; co_return true; } private: asio::awaitable simulateCal() { // 核心代码在这里 // 从这里可以看出,协程只适合能通知唤醒的阻塞,比如 socket.recv 虽然阻塞 // 但是可以被 OS 唤醒。不适合直接的阻塞比如 从一个驱动中读取数组,然后驱动很慢有阻塞这种。 // 非要用的话,需要把真正的阻塞(不是睡眠那种阻塞而是真正的耗时阻塞,比如计算)包装成异步。 // 测试可唤醒异步 // asio::steady_timer timer(io_); // timer.expires_after(std::chrono::seconds(3)); // co_await timer.async_wait(asio::use_awaitable); // 测试包装后的真正阻塞 // auto f = std::async(std::launch::async, [this]() { return realBlock(); }); // 不能这么写。 // co_await f.get(); // auto ex = co_await asio::this_coro::executor; // auto r = co_await asio::co_spawn(io_, readBlockCorouitine, asio::use_awaitable); // 这个虽然能执行,但是实际只是因为这里只有一个协程。 // co_await readBlockCorouitine(); bool result = co_await asio::co_spawn( pool_, [this]() -> asio::awaitable { co_return co_await readBlockCorouitine(); }, asio::use_awaitable); calData_ = 12; co_return true; } // 真正阻塞的函数 bool realBlock() { std::this_thread::sleep_for(std::chrono::seconds(3)); return true; } asio::awaitable readBlockCorouitine() { std::cout << "模拟耗时开启..." << std::endl; std::this_thread::sleep_for(std::chrono::seconds(3)); std::cout << "模拟耗时结束..." << std::endl; co_return true; } private: asio::io_context& io_; bool isOk_{}; int calData_{}; asio::thread_pool pool_; }; int testRunCoroutine() { asio::io_context io; WorkerCoroutine wk(io); // 使用 use_future 获取 future std::future result_future = asio::co_spawn(io, wk.Run(), // 注意:这里要传 wk.Run() 而不是 wk asio::use_future); // 在工作线程运行 io_context std::thread io_thread([&io]() { io.run(); }); std::cout << "开始异步计算,主线程可以继续...\n"; bool result = false; try { // 等待异步结果 result = result_future.get(); } catch (const std::exception& e) { std::cerr << "协程异常: " << e.what() << "\n"; } io_thread.join(); return result ? 0 : 1; // 返回 0 表示成功 } int main() { #ifdef _WIN32 SetConsoleOutputCP(CP_UTF8); #endif testRunCoroutine(); return 0; }