不推荐用std::jthread+std::promise模拟协程语义,因其本质是阻塞式多线程而非异步i/o,易卡死线程、资源泄漏且无超时重试;真正可行方案是采用已封装awaitable接口的第三方库,如boost.beast+boost.asio。

用 std::jthread + std::promise 模拟协程语义,但不推荐
标准 C++20 协程本身不提供网络 I/O 支持,co_await 无法直接挂起在 socket 等系统调用上。有人试图用 std::jthread 启动阻塞式请求、再用 std::promise 传递结果,伪造成“异步协程”——这本质是线程池+回调,不是真正异步 I/O,且容易卡死线程、资源泄漏风险高。
- 每次 GET 都新建线程,开销大;频繁请求会压垮线程数限制
-
std::promise若未被get_future()消费,析构时抛std::future_error - 无超时控制、无重试、无 HTTPS 支持,连基本错误码(如 DNS 失败)都难捕获
真正可行的路径:选一个带协程支持的 HTTP 库
目前主流方案是使用已封装好 awaitable 接口的第三方库,而非手写底层 socket 协程适配器。推荐两个生产可用选项:
-
cpp-httplib不支持协程,排除 -
boost.beast+boost.asio:C++ 标准外最成熟选择,提供async_http_client示例,其async_read/async_write均返回 awaitable 对象,可直接co_await -
libcurl+curl_easy_perform是阻塞式,但libcurl有curl_multi接口配合poll/epoll可做异步,需自己封装 awaitable —— 工程量大,仅适合已有 curl 经验者
例如用 boost.beast 发起 GET:
auto req = http::request<:string_body>{http::verb::get, "/api/data", 11};
req.set(http::field::host, "example.com");
req.set(http::field::user_agent, "MyApp/1.0");
auto stream = tcp::stream{co_await net::this_coro::executor};
co_await stream.connect(resolver.resolve("example.com", "80"));
co_await http::async_write(stream, req, use_awaitable);
auto res = http::response<:dynamic_body>{};
co_await http::async_read(stream, buffer, res, use_awaitable);
</:dynamic_body></:string_body>
编译和链接必须显式启用协程支持
即使代码写了 co_await,若编译器未开启协程特性,会报错如:error: 'co_await' is not allowed in a function that does not return a coroutine type。不同编译器处理方式不同:
- Clang:需
-std=c++20 -fcoroutines-ts(旧版)或-std=c++20 -fcoroutines(Clang 16+) - GCC 12+:需
-std=c++20 -fcoroutines,且链接-lstdc++_coro - MSVC:需
/std:c++20 /await,并确保 Windows SDK ≥ 10.0.20348.0
漏掉 -lstdc++_coro 或等效链接项,会导致运行时报 undefined reference to '__builtin_coro_*'
别忽略 SSL/TLS 和 DNS 的异步化成本
HTTP GET 看似简单,但实际链路中两个环节天然阻塞:getaddrinfo(DNS 解析)和 TLS 握手。Boost.Beast 默认用同步 getaddrinfo,虽有 net::co_spawn 封装,但需手动切到 net::ip::tcp::resolver::async_resolve;TLS 层则必须用 ssl::stream + async_handshake,否则协程会在 SSL 初始化处卡住。
常见疏忽点:
- 直接传
"https://"URL 给 HTTP 客户端,却没初始化ssl::context,导致连接失败但错误信息模糊 - DNS 超时设为 0(默认),遇到 DNS 故障时协程无限等待
- 未设置
stream.expires_after(30s),TCP 连接或读写可能 hang 住数分钟
真正轻量又现代的方案,目前还是绕不开 Boost.Beast 的 async 接口封装。自己从零实现 socket + SSL + DNS 的 awaitable 包装,调试成本远高于引入一个库。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











