使用 C++20 协程降低异步网络编程复杂度——零基础深入浅出 C++20 协程
<h1 class="mp-heading" style="padding-left: 0" data-morpho-type="heading" data-uuid="6b501df0-55ce-11ed-943d-811d3918244e" data-indent="0" data-slate-node="element"><span data-morpho-text="%E4%BC%A0%E7%BB%9F%E5%BC%82%E6%AD%A5%E5%9B%9E%E8%B0%83%20vs%20c%2B%2B20%E5%8D%8F%E7%A8%8B">传统异步回调 vs C++20协程</span></h1><div class="mp-paragraph-wrapper" style="padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0"><span style="font-size: 18px" data-morpho-text="%E5%8D%8F%E7%A8%8B%E6%98%AF%E4%B8%80%E7%A7%8D%E5%87%BD%E6%95%B0%E5%AF%B9%E8%B1%A1%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%AE%BE%E7%BD%AE%E9%94%9A%E7%82%B9%E5%81%9A%E6%9A%82%E5%81%9C%EF%BC%8C%E7%84%B6%E5%90%8E%E5%86%8D%E8%AF%A5%E9%94%9A%E7%82%B9%E6%81%A2%E5%A4%8D%E7%BB%A7%E7%BB%AD%E8%BF%90%E8%A1%8C%E3%80%82%E5%AE%83%E6%98%AF%E5%A6%82%E4%BD%95%E5%BA%94%E7%94%A8%E5%9C%A8%E7%BD%91%E7%BB%9C%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E6%96%B9%E9%9D%A2%E7%9A%84%EF%BC%8C%E8%AF%B7%E5%AF%B9%E6%AF%94%E4%B8%8B%E9%9D%A2%E7%9A%84%E4%B8%A4%E7%A7%8D%E4%BB%A3%E7%A0%81%E9%A3%8E%E6%A0%BC">协程是一种函数对象,可以设置锚点做暂停,然后再该锚点恢复继续运行。它是如何应用在网络异步编程方面的,请对比下面的两种代码风格:</span>
<div class="mp-paragraph-block-selection">
<h2 class="mp-heading" style="padding-left: 0" data-morpho-type="heading" data-uuid="66c30040-55c4-11ed-943d-811d3918244e" data-indent="0" data-slate-node="element"><span data-morpho-text="%E5%9F%BA%E4%BA%8E%E5%9B%9E%E8%B0%83%E7%9A%84%E5%BC%82%E6%AD%A5%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B">基于回调的异步网络编程</span></h2>
<div class="mp-paragraph-wrapper" style="padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0"><span style="font-size: 18px" data-morpho-text="%E5%85%88%E6%9D%A5%E7%9C%8B%E4%B8%80%E4%B8%AA%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E7%9A%84%E5%85%B8%E5%9E%8B%E4%BE%8B%E5%AD%90%20(%E4%BC%AA%E4%BB%A3%E7%A0%81)%EF%BC%9A">先来看一个异步编程的典型例子 (伪代码):</span></div>
<div class="mp-paragraph-wrapper" style="padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0">
<pre class="language-cpp highlighter-hljs"><code>async_resolve({host, port}, [](auto endpoint){
async_connect(endpoint, [](auto error_code){
async_handle_shake([](auto error_code){
send_data_ = build_request();
async_write(send_data_, [](auto error_code){
async_read();
});
});
});
});
void async_read() {
async_read(response_, [](auto error_code){
if(!finished()) {
append_response(recieve_data_);
async_read();
}else {
std::cout<<"finished ok\n";
}
});
}</code></pre>
</div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E5%9F%BA%E4%BA%8E%E5%BC%82%E6%AD%A5%E5%9B%9E%E8%B0%83%E7%9A%84%20client%20%E6%B5%81%E7%A8%8B%E5%A6%82%E4%B8%8B%EF%BC%9A">基于异步回调的 client 流程如下:</span></div>
<ul class="mp-unordered-list" data-morpho-type="unordered-list-item" data-slate-node="element">
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="%E5%BC%82%E6%AD%A5%E5%9F%9F%E5%90%8D%E8%A7%A3%E6%9E%90">异步域名解析</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="%E5%BC%82%E6%AD%A5%E8%BF%9E%E6%8E%A5">异步连接</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="%E5%BC%82%E6%AD%A5%20SSL%20%E6%8F%A1%E6%89%8B">异步 SSL 握手</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="%E5%BC%82%E6%AD%A5%E5%8F%91%E9%80%81%E6%95%B0%E6%8D%AE">异步发送数据</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="%E5%BC%82%E6%AD%A5%E6%8E%A5%E6%94%B6%E6%95%B0">异步接收数</span></div>
</div>
</li>
</ul>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E8%BF%99%E4%B8%AA%E4%BB%A3%E7%A0%81%E6%9C%89%E5%BE%88%E5%A4%9A%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%EF%BC%8C%E4%BD%BF%E7%94%A8%E5%9B%9E%E8%B0%83%E7%9A%84%E6%97%B6%E5%80%99%E8%BF%98%E6%9C%89%E4%B8%80%E4%BA%9B%E9%99%B7%E9%98%B1%EF%BC%8C%E6%AF%94%E5%A6%82%E5%A6%82%E4%BD%95%E4%BF%9D%E8%AF%81%E5%AE%89%E5%85%A8%E7%9A%84%E5%9B%9E%E8%B0%83%E3%80%81%E5%A6%82%E4%BD%95%E8%AE%A9%E5%BC%82%E6%AD%A5%E8%AF%BB%E5%AE%9E%E7%8E%B0%E5%BC%82%E6%AD%A5%E9%80%92%E5%BD%92%E8%B0%83%E7%94%A8%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%86%8D%E7%BB%93%E5%90%88%E5%BC%82%E6%AD%A5%E4%B8%9A%E5%8A%A1%E9%80%BB%E8%BE%91%EF%BC%8C%E5%9B%9E%E8%B0%83%E7%9A%84%E5%B5%8C%E5%A5%97%E5%B1%82%E6%AC%A1%E4%BC%9A%E6%9B%B4%E6%B7%B1%EF%BC%8C%E6%88%91%E4%BB%AC%E5%B7%B2%E7%BB%8F%E7%9C%8B%E5%88%B0%20callback%20hell%20%E7%9A%84%E5%BD%B1%E5%AD%90%E4%BA%86%EF%BC%81%E5%8F%AF%E8%83%BD%E4%B9%9F%E6%9C%89%E8%AF%BB%E8%80%85%E8%A7%89%E5%BE%97%E8%BF%99%E4%B8%AA%E7%A8%8B%E5%BA%A6%E7%9A%84%E5%BC%82%E6%AD%A5%E5%9B%9E%E8%B0%83%E8%BF%98%E5%8F%AF%E4%BB%A5%E6%8E%A5%E5%8F%97%EF%BC%8C%E4%BD%86%E6%98%AF%E5%A6%82%E6%9E%9C%E5%B7%A5%E7%A8%8B%E5%8F%98%E5%A4%A7%EF%BC%8C%E4%B8%9A%E5%8A%A1%E9%80%BB%E8%BE%91%E5%8F%98%E5%BE%97%E6%9B%B4%E5%8A%A0%E5%A4%8D%E6%9D%82%EF%BC%8C%E5%9B%9E%E8%B0%83%E5%B1%82%E6%AC%A1%E8%B6%8A%E6%9D%A5%E8%B6%8A%E6%B7%B1%EF%BC%8C%E7%BB%B4%E6%8A%A4%E8%B5%B7%E6%9D%A5%E5%B0%B1%E5%BE%88%E5%9B%B0%E9%9A%BE%E4%BA%86%E3%80%82">这个代码有很多回调函数,使用回调的时候还有一些陷阱,比如如何保证安全的回调、如何让异步读实现异步递归调用,如果再结合异步业务逻辑,回调的嵌套层次会更深,我们已经看到callback hell 的影子了!可能也有读者觉得这个程度的异步回调还可以接受,但是如果工程变大,业务逻辑变得更加复杂,回调层次越来越深,维护起来就很困难了。</span></div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left">
<h2 class="mp-heading" style="padding-left: 0" data-morpho-type="heading" data-uuid="689f3a50-55c4-11ed-943d-811d3918244e" data-indent="0" data-slate-node="element"><span data-morpho-text="%E5%9F%BA%E4%BA%8E%E5%8D%8F%E7%A8%8B%E7%9A%84%E5%BC%82%E6%AD%A5%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B">基于协程的异步网络编程</span></h2>
<div class="mp-paragraph-wrapper" style="padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0"><span style="font-size: 18px" data-morpho-text="%E5%86%8D%E6%9D%A5%E7%9C%8B%E7%9C%8B%E7%94%A8%E5%8D%8F%E7%A8%8B%E6%98%AF%E6%80%8E%E4%B9%88%E5%86%99%E5%90%8C%E6%A0%B7%E7%9A%84%E9%80%BB%E8%BE%91%20(%E4%BC%AA%E4%BB%A3%E7%A0%81)%EF%BC%9A">再来看看用协程是怎么写同样的逻辑 (伪代码):</span>
<div class="mp-paragraph-block-selection">
<pre class="language-cpp highlighter-hljs"><code>auto endpoint = co_await async_query({host, port});
auto error_code = co_await async_connect(endpoint);
error_code = co_await async_handle_shake();
send_data = build_request();
error_code = co_await async_write(send_data);
while(true) {
co_await async_read(response);
if(finished()) {
std::cout<<"finished ok\n";
break;
}
append_response(recieve_data_);
}</code></pre>
</div>
</div>
</div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left">
<div class="mp-paragraph-block-selection">
<div class="mp-paragraph-wrapper" style="padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-block-id="docyg-e7663071-355d-11f0-bc6f-6bf6b67b573d" data-morpho-padding="0"><span style="font-size: 18px" data-morpho-text="%E5%90%8C%E6%A0%B7%E6%98%AF%E5%BC%82%E6%AD%A5%20client%EF%BC%8C%E7%9B%B8%E6%AF%94%E5%9B%9E%E8%B0%83%E6%A8%A1%E5%BC%8F%E7%9A%84%E5%BC%82%E6%AD%A5%20client%EF%BC%8C%E6%95%B4%E4%B8%AA%E4%BB%A3%E7%A0%81%E9%9D%9E%E5%B8%B8%E6%B8%85%E7%88%BD%EF%BC%8C%E7%AE%80%E5%8D%95%E6%98%93%E6%87%82%EF%BC%8C%E5%90%8C%E6%97%B6%E4%BF%9D%E6%8C%81%E4%BA%86%E5%BC%82%E6%AD%A5%E7%9A%84%E9%AB%98%E6%80%A7%E8%83%BD%EF%BC%8C%E8%BF%99%E5%B0%B1%E6%98%AF%20C%2B%2B20%20%E5%8D%8F%E7%A8%8B%E7%9A%84%E5%A8%81%E5%8A%9B%EF%BC%81">同样是异步 client,相比回调模式的异步 client,整个代码非常清爽,简单易懂,同时保持了异步的高性能,这就是 C++20 协程的威力!</span>
<div class="mp-paragraph-block-selection">
<h1 class="mp-heading" style="padding-left: 0" data-morpho-type="heading" data-uuid="48b22870-55aa-11ed-943d-811d3918244e" data-indent="0" data-slate-node="element"><span data-morpho-text="c%2B%2B%2020%20%E5%8D%8F%E7%A8%8B%E6%8F%90%E6%A1%88%E4%B9%8B%E4%BA%89">C++ 20 协程提案之争</span></h1>
<div class="mp-paragraph-wrapper" style="padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0"><span style="font-size: 18px" data-morpho-text="%E5%8D%8F%E7%A8%8B%E5%88%86%E4%B8%BA%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%E5%92%8C%E6%9C%89%E6%A0%88%E5%8D%8F%E7%A8%8B%E4%B8%A4%E7%A7%8D">协程分为无栈协程和有栈协程两种</span></div>
<ul class="mp-unordered-list" data-morpho-type="unordered-list-item" data-slate-node="element">
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="%E6%97%A0%E6%A0%88%E6%8C%87%E5%8F%AF%E6%8C%82%E8%B5%B7%2F%E6%81%A2%E5%A4%8D%E7%9A%84%E5%87%BD%E6%95%B0">无栈指可挂起/恢复的函数</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="%E6%9C%89%E6%A0%88%E5%8D%8F%E7%A8%8B%E5%88%99%E7%9B%B8%E5%BD%93%E4%BA%8E%E7%94%A8%E6%88%B7%E6%80%81%E7%BA%BF%E7%A8%8B">有栈协程则相当于用户态线程</span></div>
</div>
</li>
</ul>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E6%9C%89%E6%A0%88%E5%8D%8F%E7%A8%8B%E5%88%87%E6%8D%A2%E7%9A%84%E6%88%90%E6%9C%AC%E6%98%AF%E7%94%A8%E6%88%B7%E6%80%81%E7%BA%BF%E7%A8%8B%E5%88%87%E6%8D%A2%E7%9A%84%E6%88%90%E6%9C%AC%EF%BC%8C%E8%80%8C%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%E5%88%87%E6%8D%A2%E7%9A%84%E6%88%90%E6%9C%AC%E5%88%99%E7%9B%B8%E5%BD%93%E4%BA%8E%E5%87%BD%E6%95%B0%E8%B0%83%E7%94%A8%E7%9A%84%E6%88%90%E6%9C%AC%E3%80%82">有栈协程切换的成本是用户态线程切换的成本,而无栈协程切换的成本则相当于函数调用的成本。</span></div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"> </div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E6%9C%89%E6%A0%88%EF%BC%88stackful%EF%BC%89%E5%8D%8F%E7%A8%8B%E9%80%9A%E5%B8%B8%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%89%8B%E6%AE%B5%E6%98%AF%E5%9C%A8%E5%A0%86%E4%B8%8A%E6%8F%90%E5%89%8D%E5%88%86%E9%85%8D%E4%B8%80%E5%9D%97%E8%BE%83%E5%A4%A7%E7%9A%84%E5%86%85%E5%AD%98%E7%A9%BA%E9%97%B4%EF%BC%88%E6%AF%94%E5%A6%82%2064K%EF%BC%89%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E5%8D%8F%E7%A8%8B%E6%89%80%E8%B0%93%E7%9A%84%E2%80%9C%E6%A0%88%E2%80%9D%EF%BC%8C%E5%8F%82%E6%95%B0%E3%80%81return%20address%20%E7%AD%89%E9%83%BD%E5%8F%AF%E4%BB%A5%E5%AD%98%E6%94%BE%E5%9C%A8%E8%BF%99%E4%B8%AA%E2%80%9C%E6%A0%88%E2%80%9D%E7%A9%BA%E9%97%B4%E4%B8%8A%E3%80%82%E5%A6%82%E6%9E%9C%E9%9C%80%E8%A6%81%E5%8D%8F%E7%A8%8B%E5%88%87%E6%8D%A2%EF%BC%8C%E9%82%A3%E4%B9%88%E9%80%9A%E8%BF%87%20swapcontext%20%E4%B8%80%E7%B1%BB%E7%9A%84%E5%BD%A2%E5%BC%8F%E6%9D%A5%E8%AE%A9%E7%B3%BB%E7%BB%9F%E8%AE%A4%E4%B8%BA%E8%BF%99%E4%B8%AA%E5%A0%86%E4%B8%8A%E7%A9%BA%E9%97%B4%E5%B0%B1%E6%98%AF%E6%99%AE%E9%80%9A%E7%9A%84%E6%A0%88%EF%BC%8C%E8%BF%99%E5%B0%B1%E5%AE%9E%E7%8E%B0%E4%BA%86%E4%B8%8A%E4%B8%8B%E6%96%87%E7%9A%84%E5%88%87%E6%8D%A2%E3%80%82">有栈(stackful)协程通常的实现手段是在堆上提前分配一块较大的内存空间(比如 64K),也就是协程所谓的“栈”,参数、return address 等都可以存放在这个“栈”空间上。如果需要协程切换,那么通过 swapcontext 一类的形式来让系统认为这个堆上空间就是普通的栈,这就实现了上下文的切换。</span>
<div class="mp-paragraph-block-selection"> </div>
</div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E6%9C%89%E6%A0%88%E5%8D%8F%E7%A8%8B%E6%9C%80%E5%A4%A7%E7%9A%84%E4%BC%98%E5%8A%BF%E5%B0%B1%E6%98%AF%E4%BE%B5%E5%85%A5%E6%80%A7%E5%B0%8F%EF%BC%8C%E4%BD%BF%E7%94%A8%E8%B5%B7%E6%9D%A5%E9%9D%9E%E5%B8%B8%E7%AE%80%E4%BE%BF%EF%BC%8C%E5%B7%B2%E6%9C%89%E7%9A%84%E4%B8%9A%E5%8A%A1%E4%BB%A3%E7%A0%81%E5%87%A0%E4%B9%8E%E4%B8%8D%E9%9C%80%E8%A6%81%E5%81%9A%E4%BB%80%E4%B9%88%E4%BF%AE%E6%94%B9%EF%BC%8C%E4%BD%86%E6%98%AF%20C%2B%2B20%20%E6%9C%80%E7%BB%88%E8%BF%98%E6%98%AF%E9%80%89%E6%8B%A9%E4%BA%86%E4%BD%BF%E7%94%A8%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%EF%BC%8C%E4%B8%BB%E8%A6%81%E5%87%BA%E4%BA%8E%E4%B8%8B%E9%9D%A2%E8%BF%99%E5%87%A0%E4%B8%AA%E6%96%B9%E9%9D%A2%E7%9A%84%E8%80%83%E8%99%91%E3%80%82">有栈协程最大的优势就是侵入性小,使用起来非常简便,已有的业务代码几乎不需要做什么修改,但是 C++20 最终还是选择了使用无栈协程,主要出于下面这几个方面的考虑:</span></div>
<h2 class="mp-heading" style="text-align: left; padding-left: 0" data-morpho-type="heading" data-uuid="24f59c60-55ae-11ed-943d-811d3918244e" data-indent="0" data-slate-node="element" data-morpho-heading-text-align="left"><span data-morpho-text="%E6%A0%88%E7%A9%BA%E9%97%B4%E7%9A%84%E9%99%90%E5%88%B6">栈空间的限制</span></h2>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E6%9C%89%E6%A0%88%E5%8D%8F%E7%A8%8B%E7%9A%84%E2%80%9C%E6%A0%88%E2%80%9D%E7%A9%BA%E9%97%B4%E6%99%AE%E9%81%8D%E6%98%AF%E6%AF%94%E8%BE%83%E5%B0%8F%E7%9A%84%EF%BC%8C%E5%9C%A8%E4%BD%BF%E7%94%A8%E4%B8%AD%E6%9C%89%E6%A0%88%E6%BA%A2%E5%87%BA%E7%9A%84%E9%A3%8E%E9%99%A9%EF%BC%9B%E8%80%8C%E5%A6%82%E6%9E%9C%E8%AE%A9%E2%80%9C%E6%A0%88%E2%80%9D%E7%A9%BA%E9%97%B4%E5%8F%98%E5%BE%97%E5%BE%88%E5%A4%A7%EF%BC%8C%E5%AF%B9%E5%86%85%E5%AD%98%E7%A9%BA%E9%97%B4%E5%8F%88%E6%98%AF%E5%BE%88%E5%A4%A7%E7%9A%84%E6%B5%AA%E8%B4%B9%E3%80%82%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%E5%88%99%E6%B2%A1%E6%9C%89%E8%BF%99%E4%BA%9B%E9%99%90%E5%88%B6%EF%BC%8C%E6%97%A2%E6%B2%A1%E6%9C%89%E6%BA%A2%E5%87%BA%E7%9A%84%E9%A3%8E%E9%99%A9%EF%BC%8C%E4%B9%9F%E6%97%A0%E9%9C%80%E6%8B%85%E5%BF%83%E5%86%85%E5%AD%98%E5%88%A9%E7%94%A8%E7%8E%87%E7%9A%84%E9%97%AE%E9%A2%98%E3%80%82">有栈协程的“栈”空间普遍是比较小的,在使用中有栈溢出的风险;而如果让“栈”空间变得很大,对内存空间又是很大的浪费。无栈协程则没有这些限制,既没有溢出的风险,也无需担心内存利用率的问题。</span></div>
<h2 class="mp-heading" style="text-align: left; padding-left: 0" data-morpho-type="heading" data-uuid="311d2ee0-55ae-11ed-943d-811d3918244e" data-indent="0" data-slate-node="element" data-morpho-heading-text-align="left"><span data-morpho-text="%E6%80%A7%E8%83%BD">性能</span></h2>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E6%9C%89%E6%A0%88%E5%8D%8F%E7%A8%8B%E5%9C%A8%E5%88%87%E6%8D%A2%E6%97%B6%E7%A1%AE%E5%AE%9E%E6%AF%94%E7%B3%BB%E7%BB%9F%E7%BA%BF%E7%A8%8B%E8%A6%81%E8%BD%BB%E9%87%8F%EF%BC%8C%E4%BD%86%E6%98%AF%E5%92%8C%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%E7%9B%B8%E6%AF%94%E4%BB%8D%E7%84%B6%E6%98%AF%E5%81%8F%E9%87%8D%E7%9A%84%EF%BC%8C%E8%BF%99%E4%B8%80%E7%82%B9%E8%99%BD%E7%84%B6%E5%9C%A8%E6%88%91%E4%BB%AC%E7%9B%AE%E5%89%8D%E7%9A%84%E5%AE%9E%E9%99%85%E4%BD%BF%E7%94%A8%E4%B8%AD%E5%BD%B1%E5%93%8D%E6%B2%A1%E6%9C%89%E9%82%A3%E4%B9%88%E5%A4%A7%EF%BC%8C%E4%BD%86%E4%B9%9F%E5%86%B3%E5%AE%9A%E4%BA%86%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%9C%A8%E4%B8%80%E4%BA%9B%E6%9B%B4%E6%9C%89%E6%84%8F%E6%80%9D%E7%9A%84%E5%9C%BA%E6%99%AF%E4%B8%8A%E3%80%82%E4%B8%BE%E4%B8%AA%E4%BE%8B%E5%AD%90%EF%BC%8CC%2B%2B20%20coroutines%20%E6%8F%90%E6%A1%88%E7%9A%84%E4%BD%9C%E8%80%85%20Gor%20Nishanov%20%E5%9C%A8%20CppCon%202018%20%E4%B8%8A%E6%BC%94%E7%A4%BA%E4%BA%86%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%E8%83%BD%E5%81%9A%E5%88%B0%E7%BA%B3%E7%A7%92%E7%BA%A7%E7%9A%84%E5%88%87%E6%8D%A2%EF%BC%8C%E5%B9%B6%E5%9F%BA%E4%BA%8E%E8%BF%99%E4%B8%AA%E7%89%B9%E7%82%B9%E5%AE%9E%E7%8E%B0%E4%BA%86%E5%87%8F%E5%B0%91%20Cache%20Miss%20%E7%9A%84%E7%89%B9%E6%80%A7%E3%80%82">有栈协程在切换时确实比系统线程要轻量,但是和无栈协程相比仍然是偏重的,这一点虽然在我们目前的实际使用中影响没有那么大,但也决定了无栈协程可以用在一些更有意思的场景上。举个例子,C++20 coroutines 提案的作者Gor Nishanov 在 CppCon 2018 上演示了无栈协程能做到纳秒级的切换,并基于这个特点实现了减少 Cache Miss 的特性。</span>
<div class="mp-paragraph-block-selection"> </div>
</div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left">
<h2 class="mp-heading" style="padding-left: 0" data-morpho-type="heading" data-uuid="326062a0-55c1-11ed-943d-811d3918244e" data-indent="0" data-slate-node="element"><span data-morpho-text="%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%E6%98%AF%E6%99%AE%E9%80%9A%E5%87%BD%E6%95%B0%E7%9A%84%E6%B3%9B%E5%8C%96">无栈协程是普通函数的泛化</span></h2>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%E6%98%AF%E4%B8%80%E4%B8%AA%E5%8F%AF%E4%BB%A5%E6%9A%82%E5%81%9C%E5%92%8C%E6%81%A2%E5%A4%8D%E7%9A%84%E5%87%BD%E6%95%B0%EF%BC%8C%E6%98%AF%E5%87%BD%E6%95%B0%E8%B0%83%E7%94%A8%E7%9A%84%E6%B3%9B%E5%8C%96%E3%80%82">无栈协程是一个可以暂停和恢复的函数,是函数调用的泛化。</span>
<div class="mp-paragraph-block-selection"> </div>
</div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E6%88%91%E4%BB%AC%E7%9F%A5%E9%81%93%E4%B8%80%E4%B8%AA%E5%87%BD%E6%95%B0%E7%9A%84%E5%87%BD%E6%95%B0%E4%BD%93%20(function%20body)%20%E6%98%AF%E9%A1%BA%E5%BA%8F%E6%89%A7%E8%A1%8C%E7%9A%84%EF%BC%8C%E6%89%A7%E8%A1%8C%E5%AE%8C%E4%B9%8B%E5%90%8E%E5%B0%86%E7%BB%93%E6%9E%9C%E8%BF%94%E5%9B%9E%E7%BB%99%E8%B0%83%E7%94%A8%E8%80%85%EF%BC%8C%E6%88%91%E4%BB%AC%E6%B2%A1%E5%8A%9E%E6%B3%95%E6%8C%82%E8%B5%B7%E5%AE%83%E5%B9%B6%E7%A8%8D%E5%90%8E%E6%81%A2%E5%A4%8D%E5%AE%83%EF%BC%8C%E5%8F%AA%E8%83%BD%E7%AD%89%E5%BE%85%E5%AE%83%E7%BB%93%E6%9D%9F%E3%80%82%E8%80%8C%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%E5%88%99%E5%85%81%E8%AE%B8%E6%88%91%E4%BB%AC%E6%8A%8A%E5%87%BD%E6%95%B0%E6%8C%82%E8%B5%B7%EF%BC%8C%E7%84%B6%E5%90%8E%E5%9C%A8%E4%BB%BB%E6%84%8F%E9%9C%80%E8%A6%81%E7%9A%84%E6%97%B6%E5%88%BB%E5%8E%BB%E6%81%A2%E5%A4%8D%E5%B9%B6%E6%89%A7%E8%A1%8C%E5%87%BD%E6%95%B0%E4%BD%93%EF%BC%8C%E7%9B%B8%E6%AF%94%E6%99%AE%E9%80%9A%E5%87%BD%E6%95%B0%EF%BC%8C%E5%8D%8F%E7%A8%8B%E7%9A%84%E5%87%BD%E6%95%B0%E4%BD%93%E5%8F%AF%E4%BB%A5%E6%8C%82%E8%B5%B7%E5%B9%B6%E5%9C%A8%E4%BB%BB%E6%84%8F%E6%97%B6%E5%88%BB%E6%81%A2%E5%A4%8D%E6%89%A7%E8%A1%8C%E3%80%82%E4%BB%8E%E8%BF%99%E4%B8%AA%E8%A7%92%E5%BA%A6%E6%9D%A5%E8%AF%B4%EF%BC%8C%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%E6%98%AF%E6%99%AE%E9%80%9A%E5%87%BD%E6%95%B0%E7%9A%84%E6%B3%9B%E5%8C%96%E3%80%82">我们知道一个函数的函数体 (function body) 是顺序执行的,执行完之后将结果返回给调用者,我们没办法挂起它并稍后恢复它,只能等待它结束。而无栈协程则允许我们把函数挂起,然后在任意需要的时刻去恢复并执行函数体,相比普通函数,协程的函数体可以挂起并在任意时刻恢复执行。从这个角度来说,无栈协程是普通函数的泛化。</span>
<div class="mp-paragraph-block-selection"> </div>
</div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span data-morpho-text="%E6%88%91%E4%BB%AC%E7%9F%A5%E9%81%93%E4%B8%80%E4%B8%AA%E5%87%BD%E6%95%B0%E7%9A%84%E5%87%BD%E6%95%B0%E4%BD%93%20(function%20body)%20%E6%98%AF%E9%A1%BA%E5%BA%8F%E6%89%A7%E8%A1%8C%E7%9A%84%EF%BC%8C%E6%89%A7%E8%A1%8C%E5%AE%8C%E4%B9%8B%E5%90%8E%E5%B0%86%E7%BB%93%E6%9E%9C%E8%BF%94%E5%9B%9E%E7%BB%99%E8%B0%83%E7%94%A8%E8%80%85%EF%BC%8C%E6%88%91%E4%BB%AC%E6%B2%A1%E5%8A%9E%E6%B3%95%E6%8C%82%E8%B5%B7%E5%AE%83%E5%B9%B6%E7%A8%8D%E5%90%8E%E6%81%A2%E5%A4%8D%E5%AE%83%EF%BC%8C%E5%8F%AA%E8%83%BD%E7%AD%89%E5%BE%85%E5%AE%83%E7%BB%93%E6%9D%9F%E3%80%82%E8%80%8C%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%E5%88%99%E5%85%81%E8%AE%B8%E6%88%91%E4%BB%AC%E6%8A%8A%E5%87%BD%E6%95%B0%E6%8C%82%E8%B5%B7%EF%BC%8C%E7%84%B6%E5%90%8E%E5%9C%A8%E4%BB%BB%E6%84%8F%E9%9C%80%E8%A6%81%E7%9A%84%E6%97%B6%E5%88%BB%E5%8E%BB%E6%81%A2%E5%A4%8D%E5%B9%B6%E6%89%A7%E8%A1%8C%E5%87%BD%E6%95%B0%E4%BD%93%EF%BC%8C%E7%9B%B8%E6%AF%94%E6%99%AE%E9%80%9A%E5%87%BD%E6%95%B0%EF%BC%8C%E5%8D%8F%E7%A8%8B%E7%9A%84%E5%87%BD%E6%95%B0%E4%BD%93%E5%8F%AF%E4%BB%A5%E6%8C%82%E8%B5%B7%E5%B9%B6%E5%9C%A8%E4%BB%BB%E6%84%8F%E6%97%B6%E5%88%BB%E6%81%A2%E5%A4%8D%E6%89%A7%E8%A1%8C%E3%80%82%E4%BB%8E%E8%BF%99%E4%B8%AA%E8%A7%92%E5%BA%A6%E6%9D%A5%E8%AF%B4%EF%BC%8C%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%E6%98%AF%E6%99%AE%E9%80%9A%E5%87%BD%E6%95%B0%E7%9A%84%E6%B3%9B%E5%8C%96%E3%80%82"><img src="https://img2024.cnblogs.com/blog/1707550/202505/1707550-20250520173847547-74240866.png"></span></div>
</div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left">
<div class="mp-paragraph-block-selection">
<h1 class="mp-heading" style="text-align: left; padding-left: 0" data-morpho-type="heading" data-uuid="5d555870-55d6-11ed-943d-811d3918244e" data-indent="0" data-slate-node="element" data-morpho-heading-text-align="left"><span data-morpho-text="%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%E5%8E%9F%E7%90%86">无栈协程原理</span></h1>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E6%9C%89%E6%A0%88%E5%8D%8F%E7%A8%8B%EF%BC%9A%E6%AF%8F%E4%B8%AA%E5%8D%8F%E7%A8%8B%E5%88%9B%E5%BB%BA%E7%9A%84%E6%97%B6%E5%80%99%E9%83%BD%E4%BC%9A%E8%8E%B7%E5%BE%97%E4%B8%80%E5%9D%97%E5%9B%BA%E5%AE%9A%E5%A4%A7%E5%B0%8F%20(%E5%A6%82%20128k)%20%E7%9A%84%E5%A0%86%E5%86%85%E5%AD%98%EF%BC%8C%E5%8D%8F%E7%A8%8B%E8%BF%90%E8%A1%8C%E7%9A%84%E6%97%B6%E5%80%99%E5%B0%B1%E6%98%AF%E4%BD%BF%E7%94%A8%E8%BF%99%E5%9D%97%E5%A0%86%E5%86%85%E5%AD%98%E5%BD%93%E4%BD%9C%E8%BF%90%E8%A1%8C%E6%A0%88%E4%BD%BF%E7%94%A8%EF%BC%8C%E5%88%87%E6%8D%A2%E6%97%B6%E5%80%99%E4%BF%9D%E5%AD%98%2F%E6%81%A2%E5%A4%8D%E8%BF%90%E8%A1%8C%E6%A0%88%E5%92%8C%E7%9B%B8%E5%BA%94%E5%AF%84%E5%AD%98%E5%99%A8"><strong>有栈协程</strong>:每个协程创建的时候都会获得一块固定大小 (如 128k) 的堆内存,协程运行的时候就是使用这块堆内存当作运行栈使用,切换时候保存/恢复运行栈和相应寄存器</span></div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E6%97%A0%E6%A0%88%E5%8D%8F%E7%A8%8B%EF%BC%9A%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%E5%B9%B6%E4%B8%8D%E6%98%AF%E9%80%9A%E8%BF%87%E5%88%87%E6%8D%A2%E6%97%B6%E4%BF%9D%E5%AD%98%2F%E6%81%A2%E5%A4%8D%E8%BF%90%E8%A1%8C%E6%A0%88%E5%92%8C%E5%AF%84%E5%AD%98%E5%99%A8%E5%AE%9E%E7%8E%B0%E7%9A%84%EF%BC%8C%E5%AE%83%E7%9A%84%E5%AE%9E%E7%8E%B0%E8%A7%81%E4%B8%8B%EF%BC%8C%E7%94%B1%E4%BA%8E%E5%8D%8F%E7%A8%8B%E7%9A%84%E6%AF%8F%E4%B8%AA%E4%B8%AD%E6%96%AD%E7%82%B9%E9%83%BD%E6%98%AF%E7%A1%AE%E5%AE%9A%EF%BC%8C%E9%82%A3%E5%85%B6%E5%AE%9E%E5%8F%AA%E9%9C%80%E8%A6%81%E5%B0%86%E5%87%BD%E6%95%B0%E7%9A%84%E4%BB%A3%E7%A0%81%E5%86%8D%E8%BF%9B%E8%A1%8C%E7%BB%86%E5%88%86%EF%BC%8C%E4%BF%9D%E5%AD%98%E5%A5%BD%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F%EF%BC%8C%E5%81%9A%E5%A5%BD%E8%B0%83%E7%94%A8%E8%BF%87%E7%A8%8B%E7%9A%84%E7%8A%B6%E6%80%81%E5%8F%98%E5%8C%96%2C%20%E4%BE%8B%E5%A6%82%EF%BC%9A"><strong>无栈协程</strong>:实现原理并不是通过切换时保存/恢复运行栈和寄存器实现的,它的实现见下,由于协程的每个中断点都是确定,那其实只需要将函数的代码再进行细分,保存好局部变量,做好调用过程的状态变化。例如:</span>
<div class="mp-paragraph-block-selection">
<pre class="language-cpp highlighter-hljs"><code>void fn(){
int a, b, c;
a = b + c;
yield();
b = c + a;
yield();
c = a + b;
}</code></pre>
<div class="mp-paragraph-wrapper" style="padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-block-id="docyg-5a5dcca1-355e-11f0-bc6f-6bf6b67b573d" data-morpho-padding="0"><span style="font-size: 18px" data-morpho-text="%E5%B0%86%E4%B8%8A%E9%9D%A2%E7%9A%84%E4%BB%A3%E7%A0%81%E8%87%AA%E5%8A%A8%E8%BD%AC%E6%8D%A2%E4%B8%BA%E4%BB%A5%E4%B8%8B%E5%BD%A2%E5%BC%8F%EF%BC%9A">将上面的代码自动转换为以下形式:</span></div>
<pre class="language-cpp highlighter-hljs"><code>Struct fn{
int a, b, c;
int __state = 0;
void resume(){
switch(__state) {
case 0:
return fn1();
case 1:
return fn2();
case 2:
return fn3();
}
}
void fn1(){
a = b + c;
}
void fn2(){
b = c + a;
}
void fn3(){
c = a + b;
}
};</code></pre>
<p><span style="font-size: 18px" data-morpho-text="%E4%B8%8A%E9%9D%A2%E5%B0%B1%E5%B0%86%E4%B8%80%E4%B8%AA%E5%8D%8F%E7%A8%8B%E5%87%BD%E6%95%B0%20fn%20%E8%BF%9B%E8%A1%8C%E5%88%87%E5%88%86%E5%90%8E%E5%8F%98%E6%88%90%E4%B8%80%E4%B8%AAStruct%EF%BC%8C%E8%BF%99%E6%A0%B7%E7%9A%84%E5%AE%9E%E7%8E%B0%E7%9B%B8%E5%AF%B9%E4%BA%8E%E6%9C%89%E6%A0%88%E5%8D%8F%E7%A8%8B%E8%80%8C%E8%A8%80%E4%BD%BF%E7%94%A8%E7%9A%84%E5%86%85%E5%AD%98%E6%9B%B4%E5%B0%91%E3%80%82%E5%BD%93%E7%84%B6%E4%B8%8A%E9%9D%A2%E5%8F%AA%E6%98%AF%E4%B8%80%E7%A7%8D%E6%BC%94%E7%A4%BA%EF%BC%8C%E5%AF%B9%E5%BA%94%E6%97%A9%E6%9C%9F%E7%9A%84%20reenter%20%E7%94%A8%E6%B3%95%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%AE%8F%E5%BA%95%E5%B1%82%E9%80%9A%E8%BF%87%20switch-case%20%E5%B0%86%E5%87%BD%E6%95%B0%E6%8B%86%E5%88%86%E6%88%90%E5%A4%9A%E4%B8%AA%E5%8F%AF%E9%87%8D%E5%85%A5%E7%82%B9%EF%BC%8C%E4%B8%80%E8%88%AC%E4%B9%9F%E7%A7%B0%E4%B8%BA%20duff%20device%E3%80%82">上面就将一个协程函数 fn 进行切分后变成一个Struct,这样的实现相对于有栈协程而言使用的内存更少。当然上面只是一种演示,对应早期的 reenter 用法,这个宏底层通过 switch-case 将函数拆分成多个可重入点,一般也称为 duff device。</span></p>
<h1 class="mp-heading" style="text-align: left; padding-left: 0" data-morpho-type="heading" data-uuid="0317d0b0-55d9-11ed-943d-811d3918244e" data-indent="0" data-slate-node="element" data-morpho-heading-text-align="left"><span data-morpho-text="c%2B%2B20%20%E5%8D%8F%E7%A8%8B%E7%BC%BA%E7%82%B9">C++20 协程缺点</span></h1>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E9%9A%BE%E4%BA%8E%E7%90%86%E8%A7%A3%E3%80%81%E8%BF%87%E4%BA%8E%E7%81%B5%E6%B4%BB%E3%80%81%E5%8A%A8%E6%80%81%E5%88%86%E9%85%8D%E5%AF%BC%E8%87%B4%E7%9A%84%E6%80%A7%E8%83%BD%E9%97%AE%E9%A2%98%E7%AD%89%E7%AD%89%E3%80%82">难于理解、过于灵活、动态分配导致的性能问题等等。</span></div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"> </div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="c%2B%2B20%20%E5%8D%8F%E7%A8%8B%E5%85%B3%E9%94%AE%E6%A6%82%E5%BF%B5%E7%B9%81%E5%A4%9A%EF%BC%9A">C++20 协程关键概念繁多:</span></div>
<ul class="mp-unordered-list" data-morpho-type="unordered-list-item" data-slate-node="element">
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="%E5%8D%8F%E7%A8%8B%E5%B8%A7%20(coroutine%20frame)">协程帧 (coroutine frame)</span></div>
</div>
<ul class="mp-unordered-list" data-morpho-type="unordered-list-item" data-slate-node="element">
<li class="mp-list-item" data-morpho-list-depth="1">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="%E5%8D%8F%E7%A8%8B%E5%8F%82%E6%95%B0">协程参数</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="1">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F">局部变量</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="1">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="promise%20%E5%AF%B9%E8%B1%A1">promise 对象</span></div>
</div>
</li>
</ul>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="promise_type">promise_type</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="coroutine%20return%20object">coroutine return object</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="std%3A%3Acoroutine_handle">std::coroutine_handle</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="co_await%E3%80%81awaiter%E3%80%81awaitable">co_await、awaiter、awaitable</span></div>
</div>
</li>
</ul>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="c%2B%2B20%20%E6%98%AF%E9%80%9A%E8%BF%87%20Compiler%20%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E4%B8%8E%E8%AF%AD%E6%B3%95%E7%B3%96%E9%85%8D%E5%90%88%E7%9A%84%E6%A8%A1%E5%BC%8F%E6%9D%A5%E5%AE%9E%E7%8E%B0%E7%9A%84%E7%9B%B8%E5%85%B3%E6%9C%BA%E5%88%B6%EF%BC%8C%E4%B8%8E%E5%85%B6%E5%AE%83%E8%AF%AD%E8%A8%80%E5%AF%B9%E6%AF%94%E4%B9%8B%E4%B8%8B%20c%2B%2B20%20%E5%8D%8F%E7%A8%8B%E4%BD%BF%E7%94%A8%E7%9A%84%E7%9B%B4%E8%A7%82%E5%BA%A6%EF%BC%8C%E4%BE%BF%E5%88%A9%E6%80%A7%E9%83%BD%E4%BC%9A%E5%AD%98%E5%9C%A8%E4%B8%80%E4%BA%9B%E6%8A%98%E6%89%A3%E3%80%82">C++20 是通过 Compiler 代码生成与语法糖配合的模式来实现的相关机制,与其它语言对比之下 C++20 协程使用的直观度,便利性都会存在一些折扣。</span>
<div class="mp-paragraph-block-selection">
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left">
<div class="mp-paragraph-block-selection"> </div>
</div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="c%2B%2B%2020%20%E5%8D%8F%E7%A8%8B%E6%A6%82%E8%A7%88%E5%9B%BE%EF%BC%9A">C++ 20 协程概览图:</span>
<div class="mp-paragraph-block-selection"><img src="https://img2024.cnblogs.com/blog/1707550/202505/1707550-20250520174056488-116432224.png"></div>
<div class="mp-paragraph-block-selection">
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-block-id="docyg-8c18d141-355e-11f0-bc6f-6bf6b67b573d" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="c%2B%2B20%20%E5%8D%8F%E7%A8%8B%E8%BF%90%E8%A1%8C%E6%B5%81%E7%A8%8B%E5%9B%BE%EF%BC%9A">C++20 协程运行流程图:</span>
<div class="mp-paragraph-block-selection"> </div>
</div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-block-id="docyg-8c18d141-355e-11f0-bc6f-6bf6b67b573d" data-morpho-padding="0" data-morpho-align="left"><span data-morpho-text="c%2B%2B20%20%E5%8D%8F%E7%A8%8B%E8%BF%90%E8%A1%8C%E6%B5%81%E7%A8%8B%E5%9B%BE%EF%BC%9A"><img src="https://img2024.cnblogs.com/blog/1707550/202505/1707550-20250520174117544-58819750.png"></span></div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-block-id="docyg-8c18d141-355e-11f0-bc6f-6bf6b67b573d" data-morpho-padding="0" data-morpho-align="left">
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-block-id="docyg-c75fd5f1-355e-11f0-bc6f-6bf6b67b573d" data-morpho-padding="0" data-morpho-align="left"> </div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-block-id="docyg-c75fd5f1-355e-11f0-bc6f-6bf6b67b573d" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E5%8F%A6%E4%B8%80%E4%B8%AA%E8%A7%86%E8%A7%92%EF%BC%9A">另一个视角:</span>
<div class="mp-paragraph-block-selection"><img src="https://img2024.cnblogs.com/blog/1707550/202505/1707550-20250520174256273-1419887507.png"></div>
<div class="mp-paragraph-block-selection">
<div class="mp-paragraph-wrapper" style="padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-block-id="docyg-e231ae31-355e-11f0-bc6f-6bf6b67b573d" data-morpho-padding="0"> </div>
<div class="mp-paragraph-wrapper" style="padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-block-id="docyg-e231ae31-355e-11f0-bc6f-6bf6b67b573d" data-morpho-padding="0"><span style="font-size: 18px" data-morpho-text="await%20%E6%B5%81%E7%A8%8B%EF%BC%9A">await 流程:</span>
<div class="mp-paragraph-block-selection"><img src="https://img2024.cnblogs.com/blog/1707550/202505/1707550-20250520174343431-1544341612.png"></div>
<div class="mp-paragraph-block-selection">
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-block-id="docyg-f277c9a1-355e-11f0-bc6f-6bf6b67b573d" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E7%9B%AE%E5%89%8D%E5%8F%AA%E9%80%82%E5%90%88%E7%BB%99%E5%BA%93%E4%BD%9C%E8%80%85%E4%BD%BF%E7%94%A8%EF%BC%8C%E5%9B%A0%E4%B8%BA%E5%AE%83%E5%8F%AA%E6%8F%90%E4%BE%9B%E4%BA%86%E4%B8%80%E4%BA%9B%E5%BA%95%E5%B1%82%E7%9A%84%E5%8D%8F%E7%A8%8B%E5%8E%9F%E8%AF%AD%E5%92%8C%E4%B8%80%E4%BA%9B%E5%8D%8F%E7%A8%8B%E6%9A%82%E5%81%9C%E5%92%8C%E6%81%A2%E5%A4%8D%E7%9A%84%E6%9C%BA%E5%88%B6%EF%BC%8C%E6%99%AE%E9%80%9A%E7%94%A8%E6%88%B7%E5%A6%82%E6%9E%9C%E5%B8%8C%E6%9C%9B%E4%BD%BF%E7%94%A8%E5%8D%8F%E7%A8%8B%E5%8F%AA%E8%83%BD%E4%BE%9D%E8%B5%96%E5%8D%8F%E7%A8%8B%E5%BA%93%EF%BC%8C%E7%94%B1%E5%8D%8F%E7%A8%8B%E5%BA%93%E6%9D%A5%E5%B1%8F%E8%94%BD%E8%BF%99%E4%BA%9B%E5%BA%95%E5%B1%82%E7%BB%86%E8%8A%82%EF%BC%8C%E6%8F%90%E4%BE%9B%E7%AE%80%E5%8D%95%E6%98%93%E7%94%A8%E7%9A%84%20API%EF%BC%8C%E4%BB%A5%E4%BE%BF%E4%B8%9A%E5%8A%A1%E4%BE%A7%E4%BD%BF%E7%94%A8%E8%B4%9F%E6%8B%85%E5%B0%BD%E5%8F%AF%E8%83%BD%E4%BD%8E">目前只适合给库作者使用,因为它只提供了一些底层的协程原语和一些协程暂停和恢复的机制,普通用户如果希望使用协程只能依赖协程库,由协程库来屏蔽这些底层细节,提供简单易用的 API,以便业务侧使用负担尽可能低。</span>
<div class="mp-paragraph-block-selection">
<h1 class="mp-heading" style="text-align: left; padding-left: 0" data-morpho-type="heading" data-uuid="9b1f8ac0-55c4-11ed-943d-811d3918244e" data-indent="0" data-slate-node="element" data-morpho-heading-text-align="left"><span data-morpho-text="%E5%8D%8F%E7%A8%8B%E5%BA%93">协程库</span></h1>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E9%80%89%E5%8F%96%E4%B8%80%E4%B8%AA%E5%90%88%E9%80%82%E7%9A%84%E5%8D%8F%E7%A8%8B%E5%BA%93%E6%9C%89%E5%8A%A9%E4%BA%8E%E5%B1%8F%E8%94%BD%20c%2B%2B20%20%E5%BA%95%E5%B1%82%E7%9A%84%E5%AE%9E%E7%8E%B0%E7%BB%86%E8%8A%82%EF%BC%8C%E5%AF%B9%E7%94%A8%E6%88%B7%E6%9B%B4%E5%8A%A0%E5%8F%8B%E5%A5%BD%EF%BC%8C%E7%9B%AE%E5%89%8D%E5%B8%82%E9%9D%A2%E4%B8%8A%E6%9C%89%E4%BB%A5%E4%B8%8B%E5%87%A0%E7%A7%8D%E9%80%89%E6%8B%A9%EF%BC%9A">选取一个合适的协程库有助于屏蔽 C++20 底层的实现细节,对用户更加友好,目前市面上有以下几种选择:</span></div>
<ul class="mp-unordered-list" data-morpho-type="unordered-list-item" data-slate-node="element">
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="boost%3A%3Aasio">boost::asio</span></div>
</div>
<ul class="mp-unordered-list" data-morpho-type="unordered-list-item" data-slate-node="element">
<li class="mp-list-item" data-morpho-list-depth="1">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="coroutine%20%2F%20reenter%20%2F%20yield%20%2F%20fork">coroutine / reenter / yield / fork</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="1">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="spawn%20%2F%20strand%20%2F%20yield_context">spawn / strand / yield_context</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="1">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="(c%2B%2B20)%20io_context%20%2F%20executor%20%2F%20co_spawn%20%2F%20co_await%20%2F%20co_return%20%2F%20use_awaitable%20%2F%20executor">(C++20) io_context / executor / co_spawn / co_await / co_return / use_awaitable / executor</span></div>
</div>
</li>
</ul>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="boost%3A%3Acoroutine2%20%5B%E6%9C%89%E6%A0%88%E5%8D%8F%E7%A8%8B%5D">boost::coroutine2 [有栈协程]</span></div>
</div>
<ul class="mp-unordered-list" data-morpho-type="unordered-list-item" data-slate-node="element">
<li class="mp-list-item" data-morpho-list-depth="1">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="coroutine%3C%3E%3A%3Apull_type%20%2F%20coroutine%3C%3E%3A%3Apush_type%20%2F%20coro_back%20%2F%20sink">coroutine<>::pull_type / coroutine<>::push_type / coro_back / sink</span></div>
</div>
</li>
</ul>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="boost%3A%3Afiber%20%5Bcoroutine2%20%2B%20%E5%8D%8F%E7%A8%8B%E8%B0%83%E5%BA%A6%E5%99%A8%20%2B%20%E5%8D%8F%E7%A8%8B%E5%90%8C%E6%AD%A5%E5%B7%A5%E5%85%B7%5D">boost::fiber </span></div>
</div>
<ul class="mp-unordered-list" data-morpho-type="unordered-list-item" data-slate-node="element">
<li class="mp-list-item" data-morpho-list-depth="1">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="fiber%20%2F%20buffered_channel%3C%3E%20%2F%20barrier%20%2F%20mutex%20%2F%20channel%20%2F%20promise%20%2F%20future%20%2F%20condition_variable%20%2F%20sleep%20%2F%20yield%20">fiber / buffered_channel<> / barrier / mutex / channel / promise / future / condition_variable / sleep / yield </span></div>
</div>
</li>
</ul>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="cppcoro%20%5Bc%2B%2B20%5D">cppcoro </span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="async_simple%20%5B%E9%98%BF%E9%87%8C%5D">async_simple [阿里]</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="libco%20%5B%E8%85%BE%E8%AE%AF%EF%BC%8C%E6%9C%89%E6%A0%88%E5%8D%8F%E7%A8%8B%5D">libco [腾讯,有栈协程]</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="libcopp%20%5B%E6%9C%89%E6%A0%88%E5%8D%8F%E7%A8%8B%5D">libcopp [有栈协程]</span></div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left">
<h1 class="mp-heading" style="text-align: left; padding-left: 0" data-morpho-type="heading" data-uuid="96730af0-55ca-11ed-943d-811d3918244e" data-indent="0" data-slate-node="element" data-morpho-heading-text-align="left"><span data-morpho-text="%E6%8E%A5%E5%85%A5">接入</span></h1>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E7%BC%96%E8%AF%91%E5%8F%82%E6%95%B0%EF%BC%9A">编译参数:</span></div>
<ul class="mp-unordered-list" data-morpho-type="unordered-list-item" data-slate-node="element">
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="-std%3Dc%2B%2B2a">-std=c++2a</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="-fcoroutines-ts">-fcoroutines-ts</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="-DASIO_STA_ALONE">-DASIO_STA_ALONE</span></div>
</div>
</li>
</ul>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left">
<div class="mp-paragraph-block-selection"> </div>
</div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E7%BC%96%E8%AF%91%E5%99%A8%E5%8E%82%E5%95%86%E6%94%AF%E6%8C%81%E6%83%85%E5%86%B5%EF%BC%9A">编译器厂商支持情况:</span></div>
<ul class="mp-unordered-list" data-morpho-type="unordered-list-item" data-slate-node="element">
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="gcc%2010">gcc 10</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="msvc">msvc</span></div>
</div>
<ul class="mp-unordered-list" data-morpho-type="unordered-list-item" data-slate-node="element">
<li class="mp-list-item" data-morpho-list-depth="1">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="1900%20(VS2015%2014.0%20%E9%83%A8%E5%88%86%E6%94%AF%E6%8C%81)">1900 (VS2015 14.0 部分支持)</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="1">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="1910%20(VS2017%2015.0%20ts%20%E6%94%AF%E6%8C%81)">1910 (VS2017 15.0 ts 支持)</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="1">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="1928%20(VS2019%2016.8)">1928 (VS2019 16.8)</span></div>
</div>
</li>
</ul>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="clang%208%20(%E9%83%A8%E5%88%86%E6%94%AF%E6%8C%81)">clang 8 (部分支持)</span></div>
</div>
</li>
</ul>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left">
<div class="mp-paragraph-block-selection"> </div>
</div>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="c%2B%2B20%20%E5%9B%9B%E5%A4%A7%E6%96%B0%E5%A2%9E%E7%89%B9%E6%80%A7">C++20 四大新增特性</span></div>
<ul class="mp-unordered-list" data-morpho-type="unordered-list-item" data-slate-node="element">
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="%E6%A6%82%E5%BF%B5%20(concept)">概念 (concept)</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="%E8%8C%83%E5%9B%B4%20(ranges)">范围 (ranges)</span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px"><strong style="font-weight: bold">协程 (coroutine)</strong></span></div>
</div>
</li>
<li class="mp-list-item" data-morpho-list-depth="0">
<div class="mp-list-item-child" style="text-align: left">
<div><span style="font-size: 18px" data-morpho-text="%E6%A8%A1%E5%9D%97%20(modules)">模块 (modules)</span></div>
</div>
</li>
</ul>
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-padding="0" data-morpho-align="left">
<div class="mp-paragraph-block-selection">
<h1 class="mp-heading" style="text-align: left; padding-left: 0" data-morpho-type="heading" data-uuid="0eb29b40-55d3-11ed-943d-811d3918244e" data-indent="0" data-slate-node="element" data-morpho-block-id="docyg-12e2bce1-355f-11f0-bc6f-6bf6b67b573d" data-morpho-heading-text-align="left"><span data-morpho-text="%E5%AE%9E%E4%BE%8B">实例</span></h1>
<div data-morpho-drag-copy="true">
<div class="mp-paragraph-wrapper" style="text-align: left; padding-left: 0; --indent-pixels: 0px" data-morpho-type="paragraph" data-slate-node="element" data-morpho-block-id="docyg-171bd2b1-355f-11f0-bc6f-6bf6b67b573d" data-morpho-padding="0" data-morpho-align="left"><span style="font-size: 18px" data-morpho-text="%E5%9F%BA%E4%BA%8E%20boost%3A%3Aasio%20c%2B%2B20%20%E5%8D%8F%E7%A8%8B%E5%AE%9E%E7%8E%B0%E7%9A%84%20echo%20%E6%9C%8D%E5%8A%A1%EF%BC%9A">基于 boost::asio C++20 协程实现的 echo 服务:</span>
<div class="mp-paragraph-block-selection">
<pre class="language-cpp highlighter-hljs"><code>#include <asio/co_spawn.hpp>
#include <asio/detached.hpp>
#include <asio/io_context.hpp>
#include <asio/ip/tcp.hpp>
#include <asio/signal_set.hpp>
#include <asio/write.hpp>
#include <cstdio>
#include <iostream>
using asio::ip::tcp;
using asio::awaitable;
using asio::co_spawn;
using asio::detached;
using asio::use_awaitable;
namespace this_coro = asio::this_coro;
#if defined(ASIO_ENABLE_HANDLER_TRACKING)
# define use_awaitable \
asio::use_awaitable_t(__FILE__, __LINE__, __PRETTY_FUNCTION__)
#endif
awaitable<void> echo(tcp::socket socket)
{
try
{
char data;
for (;;)
{
std::size_t n = co_await socket.async_read_some(asio::buffer(data), use_awaitable);
co_await async_write(socket, asio::buffer(data, n), use_awaitable);
}
}
catch (std::exception& e)
{
std::printf("echo Exception: %s\n", e.what());
}
}
void fn2(){
std::cout<<"hhh\n";
}
void fn(){
fn2();
}
awaitable<void> listener()
{
auto executor = co_await this_coro::executor;
fn();
tcp::acceptor acceptor(executor, {tcp::v4(), 8988});
for (;;)
{
tcp::socket socket = co_await acceptor.async_accept(use_awaitable); //调用协程,体现同步性
co_spawn(executor, echo(std::move(socket)), detached);// 创建连接处理线程
}
}
int main()
{
try
{
asio::io_context io_context(1);
asio::signal_set signals(io_context, SIGINT, SIGTERM);
signals.async_wait([&](auto, auto){ io_context.stop(); });
co_spawn(io_context, listener(), detached); // 创建纤程,体现并发性
io_context.run(); // 开始调度
}
catch (std::exception& e)
{
std::printf("Exception: %s\n", e.what());
}
}</code></pre>
<p> </p>
</div>
</div>
<h1 class="mp-heading" style="text-align: left; padding-left: 0" data-morpho-type="heading" data-uuid="c6ec8bb0-55c6-11ed-943d-811d3918244e" data-indent="0" data-slate-node="element" data-morpho-heading-text-align="left"><span data-morpho-text="%E5%8F%82%E8%80%83">参考</span></h1>
<p><span style="font-size: 18px" data-morpho-text="%E5%8F%82%E8%80%83">. 在 Boost.Asio 中使用协程</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">C++20协程原理和应用</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">C++网络编程之asio(五)——在asio中使用协程</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">C++20协程不完全指南</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">深入浅出c++协程</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">协程的原理(Coroutine Theory)</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">聊聊协程的发展历程</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">asio服务器模式:协程</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">C++中的yield和reenter和fork</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">Boost中的协程—Boost.Asio中的coroutine类</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">如何在C++17中实现stackless coroutine以及相关的任务调度器</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">C++20 Coroutine实例教学</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">译:你的第一个协程程序(Your first coroutine)</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">ASIO 与协程</span></p>
<p><span style="font-size: 18px">. </span><span style="font-size: 18px">C++ compiler support</span></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="MySignature" role="contentinfo">
<p>本文来自博客园,作者:goodcitizen,转载请注明原文链接:https://www.cnblogs.com/goodcitizen/p/18887511/reduce_the_complexity_of_network_programming_asynchronously_with_cpp20_coroutines</p><br><br>
来源:https://www.cnblogs.com/goodcitizen/p/18887511/reduce_the_complexity_of_network_programming_asynchronously_with_cpp20_coroutines
頁:
[1]