<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Seastar on Laputa</title><link>https://chenjianyong.com/zh/series/seastar/</link><description>Recent content in Seastar on Laputa</description><generator>Hugo</generator><language>zh</language><lastBuildDate>Fri, 08 May 2026 00:21:55 +0100</lastBuildDate><atom:link href="https://chenjianyong.com/zh/series/seastar/index.xml" rel="self" type="application/rss+xml"/><item><title>Seastar: sharded service(2)</title><link>https://chenjianyong.com/zh/blog/2022/seastar-sharded-service2/</link><pubDate>Thu, 15 Dec 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-sharded-service2/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;&lt;a href="blog/2022/seastar-sharded-service1/"&gt;第一篇&lt;/a&gt;里面介绍了一下 &lt;code&gt;seastar::sharded&lt;/code&gt; 的基本概念和用法, 一般情况下我们用这些就足够了, 但是 Seastar 还为其他一些特殊的使用场景提供了支持, 当程序功能越来越复杂, 碰到这些场景的概率肯定会更大, 所以从完备的层面考虑, 还是得介绍一些他们; 其实也并不困难, Seastar 是秉持实用主义的, 也就是说在里面的组件一定是有现实中的使用场景的, 用到他们只是时间的问题(了解了这些组件之后可以在 &lt;a href="https://github.com/redpanda-data/redpanda"&gt;redpanda&lt;/a&gt; 和 &lt;a href="https://github.com/scylladb/scylladb"&gt;scylladb&lt;/a&gt; 的 codebase 里搜索一下具体的使用场景)&lt;/p&gt;
&lt;h2 id="sharded-parameter"&gt;sharded parameter&lt;/h2&gt;
&lt;p&gt;前面并没有特别说明 &lt;code&gt;seastar::sharded&lt;/code&gt; 的 &lt;code&gt;start()&lt;/code&gt; 以及 &lt;code&gt;invoke_on_*&lt;/code&gt; 系列函数允许传递哪些参数, 笼统地说只要是支持拷贝构造的类型(包括内置数据类型)都支持, 但是可以更具体地分为三类:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;arbitrary constant values - these are copied to all instances&lt;/li&gt;
&lt;li&gt;other &lt;code&gt;sharded&amp;lt;&amp;gt;&lt;/code&gt; values - these are transformed before passing to the functor; the local instance is extracted and passed&lt;/li&gt;
&lt;li&gt;shard-dependent parameter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第一类是最简单也是也是最常用的, 所有除了第二类和第三类说明的类型(&lt;code&gt;sharded&lt;/code&gt; 和 &lt;code&gt;sharded_parameter&lt;/code&gt;)外的其他类型都属于第一类, 比如 &lt;code&gt;int&lt;/code&gt;、&lt;code&gt;std::string&lt;/code&gt; 以及自定义类型 &lt;code&gt;class Widget&lt;/code&gt; 等, 他们会被拷贝到各个 shard&lt;/p&gt;</description></item><item><title>Seastar: sharded service(1)</title><link>https://chenjianyong.com/zh/blog/2022/seastar-sharded-service1/</link><pubDate>Thu, 01 Dec 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-sharded-service1/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;Seastar 是一个多线程异步库, 基于它的 App 通常都有在多个 shard(也称 logic core) 上对称部署服务的诉求; 为此我们需要在多个 shard 上创建服务的实例, 并且让这些实例执行某些操作; 这些涉及到 shard 之间的通信, Seastar 提倡使用显式的消息传递(message passing)而不是传统多线程编程常用的共享内存&amp;amp;加锁的方式进行通信, 为此提供了 &lt;code&gt;smp&lt;/code&gt; 工具; 所以我们其实可以这样写:&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;resive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;smp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;smp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;invoke_on_all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;this_shard_id&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;使用 &lt;code&gt;smp&lt;/code&gt; 中的工具, 我们可以实现这些操作, 但是如果有很多这样的服务, 那么就需要重复大量类似的代码(以上代码只是该场景下很小的一部分), 所以我们应该将其沉淀为一个通用的组件, 而 Seastar 也是这样做的, 这就是 &lt;code&gt;seastar::sharded&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;一开始它并不叫这个名字, 而是 &lt;code&gt;seastar::distributed&lt;/code&gt;, 即分布式服务, 后面考虑到 distributed 经常用于跨机器的场景, 而这里实际上是同机器跨核, 所以改名为 &lt;code&gt;seastar::sharded&lt;/code&gt;, 不过考虑到向前兼容还是把 &lt;code&gt;seastar::distributed&lt;/code&gt; 作为 &lt;code&gt;seastar::sharded&lt;/code&gt; 的一个别名保留, 只是不再推荐使用&lt;/p&gt;
&lt;h2 id="一个-"&gt;一个 🌰&lt;/h2&gt;
&lt;p&gt;在了解它的实现之前, 先看看它的一些用法, Seastar 提供了一个简易的 HTTP server, 以此为例, 看看如何使用 &lt;code&gt;sharded&lt;/code&gt; 在多个 core 上部署它; 为了简化逻辑, 使用 &lt;code&gt;seastar::async&lt;/code&gt; 以串行的方式写:&lt;/p&gt;</description></item><item><title>Seastar: network stack</title><link>https://chenjianyong.com/zh/blog/2022/seastar-network-stack/</link><pubDate>Sun, 13 Nov 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-network-stack/</guid><description>&lt;h1 id="seastar-network-stack"&gt;Seastar: network stack&lt;/h1&gt;
&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;Seastar 中提供了两种协议栈:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;native stack&lt;/li&gt;
&lt;li&gt;posix stack&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中 native stack 是 seastar 自己实现的一套协议栈, 一般是和 DPDK 配合使用; 而 posix stack 则是传统的内核协议栈; 由于我并不了解 DPDK, 暂时也没有学习/使用的需要, 所以目前还是先关注 posix stack 的实现(只关注 TCP, unix socket/UDP/SCTP 暂时不管), 以及 seastar 是如何抽象 network stack 这个概念从而统一 native stack 和 posix stack 二者的.&lt;/p&gt;
&lt;h2 id="network-stack-api"&gt;network stack API&lt;/h2&gt;
&lt;p&gt;为了统一 native stack 与 posix stack, seastar net 模块中抽象除了如下实体：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;socket&lt;/code&gt;: 可以视作调用了 &lt;code&gt;socket(2)&lt;/code&gt; 但是还没有 &lt;code&gt;connect(2)&lt;/code&gt; 的 fd, 通过它我们可以发起网络连接得到 &lt;code&gt;connected_socket&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;connected_socket&lt;/code&gt;: 一个处于连接状态的 TCP/SCTP 全双工流&lt;/li&gt;
&lt;li&gt;&lt;code&gt;server_socket&lt;/code&gt; : TCP/SCTP 监听描述符, 等待 &lt;code&gt;accept(2)&lt;/code&gt; 新的网络连接&lt;/li&gt;
&lt;li&gt;&lt;code&gt;udp_channel&lt;/code&gt;: udp 管道, 用于读写数据&lt;/li&gt;
&lt;li&gt;&lt;code&gt;udp_datagram&lt;/code&gt;: udp 数据报&lt;/li&gt;
&lt;li&gt;&lt;code&gt;network_stack&lt;/code&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="socket"&gt;socket&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;This class is responsible for establishing a connection between two endpoints. It allows for the connection attempt to be canceled.&lt;/p&gt;</description></item><item><title>Seastar: temporary buffer</title><link>https://chenjianyong.com/zh/blog/2022/seastar-temporary-buffer/</link><pubDate>Sat, 16 Jul 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-temporary-buffer/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;temporary_buffer&lt;/code&gt; 是 Seastar 提供的一种自我管理(self-managed)字节缓冲区，它类似于 &lt;code&gt;std::string&lt;/code&gt; 或者 &lt;code&gt;std::unique_ptr&amp;lt;char[]&amp;gt;&lt;/code&gt;，但是提供了一些更加灵活的内存管理机制，比如它可以独占底层的缓冲区，也可以和其他 &lt;code&gt;temporary_buffer&lt;/code&gt; 共享底层缓冲区、甚至只共享其他 &lt;code&gt;temporay_buffer&lt;/code&gt; 底层缓冲区的一部分&amp;hellip;，因为这些功能，这个数据结构在 Seastar 以及 Scylla/RedPanda 等基于 Seastar 的项目中使用得非常广泛&lt;/p&gt;
&lt;h2 id="temporary-buffer"&gt;temporary buffer&lt;/h2&gt;
&lt;p&gt;首先来看看其结构定义：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;typename&lt;/span&gt; &lt;span class="n"&gt;CharType&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;temporary_buffer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;CharType&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;deleter&lt;/span&gt; &lt;span class="n"&gt;_deleter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;非常简单的一个结构，其中 &lt;code&gt;_buffer&lt;/code&gt; 就是其底层缓冲区，&lt;code&gt;_size&lt;/code&gt; 就是该缓冲区的大小；但是需要注意的是，由于 &lt;code&gt;temporay_buffer&lt;/code&gt; 是可以从其他 &lt;code&gt;temporary_buffer&lt;/code&gt; 共享的(甚至只共享一部分)，所以 &lt;code&gt;_buffer&lt;/code&gt; 可能并是最初分配的内存的起始地址，因此 &lt;code&gt;_size&lt;/code&gt; 也可能并不是最初分配内存的大小&lt;/p&gt;
&lt;p&gt;二者的关系可能是这样：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;
 &lt;source type="image/webp" srcset="https://chenjianyong.com/images/blog/seastar/seastar-temporary-buffer_hu_5f46bdf3c0deddae.webp 480w, https://chenjianyong.com/images/blog/seastar/seastar-temporary-buffer_hu_7fcf4ae892236f2c.webp 768w, https://chenjianyong.com/images/blog/seastar/seastar-temporary-buffer_hu_19ce598040831c11.webp 1046w" sizes="(max-width: 720px) 100vw, 720px"&gt;
 &lt;img src="https://chenjianyong.com/images/blog/seastar/seastar-temporary-buffer_hu_31935ecab70356bd.png"
 alt="seastar-temporary-buffer"
 width="1046" height="502"
 loading="lazy" decoding="async"&gt;
 &lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;而 &lt;code&gt;deleter&lt;/code&gt; 自然就是用来释放该内存的工具了，相关逻辑暂且按下不表，后面会用另外一个 &lt;a href="https://chenjianyong.com/zh/blog/2022/seastar-temporary-buffer/#deleter"&gt;section&lt;/a&gt; 来解读，还是很有趣的&lt;/p&gt;
&lt;h3 id="构造--析构"&gt;构造 &amp;amp; 析构&lt;/h3&gt;
&lt;p&gt;首先来看看它的构造和析构函数：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;explicit&lt;/span&gt; &lt;span class="nf"&gt;temporary_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CharType&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CharType&lt;/span&gt;&lt;span class="p"&gt;)))),&lt;/span&gt; &lt;span class="n"&gt;_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_deleter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;make_free_deleter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;bad_alloc&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;temporary_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CharType&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;deleter&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;noexcept&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;_deleter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;temporary_buffer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;noexcept&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;一个是默认构造函数，另一个则是指定缓冲区的大小，然后用 &lt;code&gt;malloc&lt;/code&gt; 分配指定大小的缓冲区，此时 &lt;code&gt;deleter&lt;/code&gt; 通过 &lt;code&gt;make_free_deleter&lt;/code&gt; 构造出来，它的功能和它的名字一样：通过 &lt;code&gt;std::free&lt;/code&gt; 释放 &lt;code&gt;_buffer&lt;/code&gt;；还有一个则是直接传入 raw buffer 和 size，以及自定义&lt;code&gt;deleter&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Seastar: 用户线程</title><link>https://chenjianyong.com/zh/blog/2022/seastar-%E7%94%A8%E6%88%B7%E7%BA%BF%E7%A8%8B/</link><pubDate>Sun, 22 May 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-%E7%94%A8%E6%88%B7%E7%BA%BF%E7%A8%8B/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;通常我们在 seastar 中写代码是不能阻塞的，如果我们希望在一段异步代码之后执行完毕之后开始执行另外一个逻辑，那么我们就需要通过 continuation 的方式将其串联起来，比如：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;seastar&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;([]()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cm"&gt;/* another code piece */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;而不能直接调用 &lt;code&gt;future::get()&lt;/code&gt; 或者 &lt;code&gt;future::wait()&lt;/code&gt;：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;seastar&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt;/* another code piece */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;以上代码在 &lt;code&gt;wait()&lt;/code&gt; 的过程中就会 core dump。&lt;/p&gt;
&lt;p&gt;但是 seastar 提供了 &lt;code&gt;seastar::thread&lt;/code&gt; 这个工具，通过它，我们可以正常执行可能导致阻塞(即 &lt;code&gt;future::wait()&lt;/code&gt;)的代码：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt; &lt;span class="n"&gt;th&lt;/span&gt;&lt;span class="p"&gt;([]()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;chrono_literals&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Hello, seastar thread!&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;do_with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;th&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="n"&gt;seastar&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;th&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;th&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;实际上其内部并没有阻塞，但是却产生了以同步方式写异步代码的效果(通过 &lt;code&gt;ucontext&lt;/code&gt;)，有点 async/await 的感觉；这个工具在单测中用的非常普遍，而且像 scylla 和 redpanda 的 &lt;code&gt;main&lt;/code&gt; 函数都是通过它启动的。&lt;/p&gt;
&lt;h2 id="seastarasync"&gt;&lt;code&gt;seastar::async&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;虽然我们可以像上面一样直接使用 &lt;code&gt;seastar::thread&lt;/code&gt;，但是却要处理等待 thread 结束(&lt;code&gt;join()&lt;/code&gt;)、生命周期管理等问题，所以 seastar 更推荐我们使用 &lt;code&gt;seastar::async&lt;/code&gt; 这个函数，比如之前的代码通过该函数可以改写成这样：&lt;/p&gt;</description></item><item><title>Seastar: semaphore</title><link>https://chenjianyong.com/zh/blog/2022/seastar-semaphore/</link><pubDate>Wed, 04 May 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-semaphore/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;最近在实现 &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API"&gt;fetch 接口&lt;/a&gt;时, 需要对单个 JS 脚本的单次执行过程中可以发起的 fetch 操作数进行限制(和 CloudFlare Workers &lt;a href="https://developers.cloudflare.com/workers/platform/limits/#simultaneous-open-connections"&gt;类似&lt;/a&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;总量限制：超过了则后续的 fetch 操作都将直接失败&lt;/li&gt;
&lt;li&gt;并发限制：超过了则后续的 fetch 请求将会被延迟(postpone)执行，直到有其他执行着的 fetch 请求结束&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第一点很简单, 用一个计数器即可解决; 关键在于第二个, 要将超出了并发限制的 fetch 操作阻塞住, 直到有其他 fetch 操作结束(即返回的 promise 被 resolve)再唤醒它们执行.&lt;/p&gt;
&lt;p&gt;这个需求听起来似乎很熟悉？可以换一种说法，将「同一个时刻可运行的 fetch 请求」视为一种资源，这个资源是可以重复利用的(这一点是并发限制和总量限制的主要区别)：发起一个 fetch 请求相当于拿走一份资源，结束一个 fetch 请求相当于归还一份资源；且这个资源并非无限，所以当资源被拿完之后再想拿就等着直到有人归还资源。&lt;/p&gt;
&lt;p&gt;说到这里就很清晰了，这个问题就是信号量(semaphore)&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;要解决的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In computer science, a semaphore is a variable or abstract data type used to control access to a common resource by multiple threads and avoid critical section problems in a concurrent system such as a multitasking operating system.&lt;/p&gt;</description></item><item><title>Seastar: 系统调用线程</title><link>https://chenjianyong.com/zh/blog/2022/seastar-%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%E7%BA%BF%E7%A8%8B/</link><pubDate>Mon, 18 Apr 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%E7%BA%BF%E7%A8%8B/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;在 Seastar 中，文件相关的操作并不直接由 reactor 线程(工作线程)执行，而是被 offload 到一个专门的线程中去执行，为此 Seastar 在 &lt;code&gt;reactor&lt;/code&gt; 中提供了诸多文件操作相关的方法；比如重命名一个文件就可以使用 &lt;code&gt;rename_file&lt;/code&gt; 方法：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rename_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;hello.txt&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;world.txt&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then_wrapped&lt;/span&gt;&lt;span class="p"&gt;([](&lt;/span&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;rename file failed: {}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_exception&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_ready_future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;所有这些文件操作相关的函数都返回 future&lt;/p&gt;
&lt;h2 id="源码剖析"&gt;源码剖析&lt;/h2&gt;
&lt;p&gt;每个 reactor 中都有一个类型为 &lt;code&gt;thread_pool&lt;/code&gt; 的变量，但是我觉得有点名不副实，因为它并不是一个 pool，而只是一个单独的线程——仅仅用于执行文件相关的 syscall，所以叫 syscall thread 或许会更好一些；不过这些都是细枝末节，先看看 &lt;code&gt;rename_file&lt;/code&gt; 的实现：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;reactor&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;rename_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string_view&lt;/span&gt; &lt;span class="n"&gt;old_pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string_view&lt;/span&gt; &lt;span class="n"&gt;new_pathname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;noexcept&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Allocating memory for a sstring can throw, hence the futurize_invoke
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;futurize_invoke&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;old_pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_pathname&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;_thread_pool&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;submit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;syscall_result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;old_pathname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old_pathname&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;new_pathname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_pathname&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrap_syscall&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old_pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;new_pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_str&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;old_pathname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;old_pathname&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;new_pathname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sstring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_pathname&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;syscall_result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;sr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;throw_fs_exception_if_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;rename failed&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;old_pathname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_pathname&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;make_ready_future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;逻辑非常简单，就是往 syscall thread 中提交一个任务，该任务也不过是简单地调用了一下 &lt;code&gt;rename&lt;/code&gt;&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt; 这个系统调用；如果该调用出错，则抛出异常——当然被 &lt;code&gt;futurize_invoke&lt;/code&gt; 捕获并转换为一个 exceptional future 返回给调用方。&lt;/p&gt;</description></item><item><title>Seastar：核间通信</title><link>https://chenjianyong.com/zh/blog/2022/seastar%E6%A0%B8%E9%97%B4%E9%80%9A%E4%BF%A1/</link><pubDate>Sat, 02 Apr 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar%E6%A0%B8%E9%97%B4%E9%80%9A%E4%BF%A1/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;虽然 Seastar 号称 share-nothing&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;，但是现代服务器开发中仍免不了需要核间通信；Seastar 为此在 &lt;code&gt;smp&lt;/code&gt; 类中提供了 &lt;code&gt;submit_to&lt;/code&gt; 方法用于向其他线程的 reactor 提交任务并执行：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;futurize_t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;invoke_result_t&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;submit_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;noexcept&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;比如下面的代码：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;run on shard-&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;this_shard_id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;smp&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;submit_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;run on shard-&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;this_shard_id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;首先在当前 shard 打印其 id，然后往 id 为 1 的 shard 提交一个异步任务，该异步任务也只是简单地打印出所在 shard 的 id&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;app_template&lt;/code&gt; 执行该函数得到结果：&lt;/p&gt;
&lt;figure class="code" data-lang="shell"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;shell&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;% sudo ./my_app -c &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;run on shard-0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;run on shard-1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;的确第二句 &lt;code&gt;std::cout&lt;/code&gt; 是在 shard-1 上执行的；这里需要注意由于使用了两个 shard，所以至少需要使用两个核(&lt;code&gt;-c 2&lt;/code&gt;)。&lt;/p&gt;
&lt;h2 id="源码剖析"&gt;源码剖析&lt;/h2&gt;
&lt;p&gt;这里涉及到两个核之间的通信，所以有必要先规定几个叫法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;local core&lt;/strong&gt;/&lt;strong&gt;local shard&lt;/strong&gt;/&lt;strong&gt;local reactor&lt;/strong&gt;：指发起通信的一方&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;remote core&lt;/strong&gt;/&lt;strong&gt;remote shard&lt;/strong&gt;/&lt;strong&gt;remote reactor&lt;/strong&gt;：指接收方&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;前面提到的 &lt;code&gt;submit_to&lt;/code&gt; 函数实际上是以默认的 &lt;code&gt;smp_submit_to_options&lt;/code&gt; 参数调用的下面这个函数：&lt;/p&gt;</description></item><item><title>Seastar: loop utility</title><link>https://chenjianyong.com/zh/blog/2022/seastar-loop-utility/</link><pubDate>Sat, 26 Mar 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-loop-utility/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;循环是绝大多数编程语言中必不可少的控制结构，比如 C++ 对数组中的元素求和：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ints&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;ints&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;ints&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;然而在 Seastar 中，写循环却不是一件容易的事情——当然不是上面这种不涉及到任何的异步操作的循环，而是指循环重复执行一个异步操作。比如我们想实现这样一个 &lt;code&gt;search&lt;/code&gt; 函数：它依次从 Google、Bing 和 Baidu 搜索，有一个成功则将其内容输出至标准输出并停止搜索；或许我们可以马上写出下面这样一段代码：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;domains&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;www.google.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;www.bing.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;www.baidu.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;fut&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_failed&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get0&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;然而 &lt;code&gt;fetch&lt;/code&gt; 函数是一个异步操作，也就是说，这个函数不会阻塞，而是立即返回；而它返回的 &lt;code&gt;future&lt;/code&gt; 很大程度上不是 ready 的，所以我们无法判断其状态，除非我们等待，然而这就失去了异步的意义(而且 Seastar 不允许我们在非 &lt;code&gt;seastar::thread&lt;/code&gt; 环境中等待一个 future)。&lt;/p&gt;
&lt;p&gt;再退一步，就算我们不考虑「有一个成功则返回」这个逻辑，而只是「依次向 Google、Bing 和 Baidu 发起请求」，我们也做不到：&lt;/p&gt;
&lt;figure class="code" data-lang="c&amp;#43;&amp;#43;"&gt;
 &lt;figcaption&gt;&lt;span class="code-lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;&lt;button class="code-copy" type="button" aria-label="复制代码"&gt;Copy&lt;/button&gt;
 &lt;/figcaption&gt;
 &lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domains&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="n"&gt;then_wrapped&lt;/span&gt;&lt;span class="p"&gt;([](&lt;/span&gt;&lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;fetch FAILED: &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_exception&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;fetch SUCCEEDED: &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;fut&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get0&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;p&gt;还是之前的原因，&lt;code&gt;fetch&lt;/code&gt; 是一个异步操作不会阻塞而是直接返回，所以这里无法保证「在前一个操作完成之后再进行下一个」这个逻辑。&lt;/p&gt;</description></item><item><title>Seastar: FPC(2)</title><link>https://chenjianyong.com/zh/blog/2022/seastar-fpc2/</link><pubDate>Wed, 09 Mar 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-fpc2/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;这里不打算完整地解释 Seastar 中 future&amp;amp;promise 的实现，里面旁枝末节实在太多，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API 的兼容性处理&lt;/li&gt;
&lt;li&gt;针对不同平台的优化&lt;/li&gt;
&lt;li&gt;针对 Debug 编译的特殊处理&lt;/li&gt;
&lt;li&gt;各种 Modern C++ 特性的使用&lt;/li&gt;
&lt;li&gt;针对 GCC/Clang 做的各种编译优化&lt;/li&gt;
&lt;li&gt;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以还是希望抓住其中的一些重难点以及做的一些优化进行分析。&lt;/p&gt;
&lt;p&gt;这个系列的第一篇文章&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;中已经 future&amp;amp;promise 的大致实现流程进行了解释，Seastar 整体思想与之类似，但是还是有一些不同&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Seastar 作为一个网络框架，绝大多数时候面对的是重 I/O 的任务，所以它并不使用扩展性并不强的多线程模型，而是采用事件驱动的方式异步执行用户代码&lt;/li&gt;
&lt;li&gt;因为 future&amp;amp;promise 都在同一个线程中操作，所以也不需要加锁，所以忘记前面的 &lt;code&gt;std::mutex&lt;/code&gt; 和 &lt;code&gt;std::condition_variable&lt;/code&gt; 吧&lt;/li&gt;
&lt;li&gt;为了极致的性能，Seastar 中的 future&amp;amp;promise 并不需要动态分配内存，所以也忘记前面的 &lt;code&gt;std::shared_ptr&amp;lt;SharedState&amp;gt;&lt;/code&gt; 吧&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="类层次结构"&gt;类层次结构&lt;/h2&gt;
&lt;p&gt;首先看看 FPC 的类结构，这里直接放出其 UML 图：&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;
 &lt;source type="image/webp" srcset="https://chenjianyong.com/images/blog/seastar/seastar-fpc-uml_hu_a016ba05752c9aee.webp 480w, https://chenjianyong.com/images/blog/seastar/seastar-fpc-uml_hu_fe1e72db127b839d.webp 768w, https://chenjianyong.com/images/blog/seastar/seastar-fpc-uml_hu_bb6f955109cec636.webp 1280w, https://chenjianyong.com/images/blog/seastar/seastar-fpc-uml_hu_7b7466710f4489e3.webp 1540w" sizes="(max-width: 720px) 100vw, 720px"&gt;
 &lt;img src="https://chenjianyong.com/images/blog/seastar/seastar-fpc-uml_hu_3488a1929f2373bd.png"
 alt="seastar-fpc-uml"
 width="1540" height="1168"
 loading="lazy" decoding="async"&gt;
 &lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;非常复杂的层次结构，关于图片有几点注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对于模板类，在 UML 图矩形的右上角标注了其模板类型参数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;uninitialized_wrapper_base&lt;/code&gt; 有两种偏特化实现，但是这里只标注了其一&lt;/li&gt;
&lt;li&gt;存在 &lt;code&gt;public&lt;/code&gt; 和 &lt;code&gt;private&lt;/code&gt; 继承，但是在 UML 图中没有表示出来&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从之前的 &lt;code&gt;SharedState&lt;/code&gt; 我们可以总结出，&lt;code&gt;future&lt;/code&gt; 和 &lt;code&gt;proimise&lt;/code&gt; 的共享状态需要包含 &lt;code&gt;future&lt;/code&gt; 的状态，异常值、数据；在 Seastar 中这一角色由 &lt;code&gt;future_state&lt;/code&gt; 承担：其中数据从 &lt;code&gt;uninitialize_wrapper&lt;/code&gt; 中继承，状态、异常值则从 &lt;code&gt;future_state_base&lt;/code&gt; 中继承。&lt;/p&gt;</description></item><item><title>Seastar: FPC(1)</title><link>https://chenjianyong.com/zh/blog/2022/seastar-fpc1/</link><pubDate>Sun, 06 Mar 2022 00:00:00 +0000</pubDate><guid>https://chenjianyong.com/zh/blog/2022/seastar-fpc1/</guid><description>&lt;h2 id="preface"&gt;Preface&lt;/h2&gt;
&lt;p&gt;主要讲的是 future&amp;amp;promise 一些基本概念以及设计原理，但是因为 Seastar 中的实现&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;非常复杂(毕竟是工业级产品，且经过了 LLVM 大牛的大量优化，多了许多与核心实现其实并没有关系的逻辑)，所以我并不打算直接硬上(其实之前尝试过好几次，但是看完了之后还是迷迷糊糊一知半解，所以打算换一种方法)，而是打算借助 CppCon 2015 上的一个 presentation&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt; 来介绍它的基本原理和简易实现；BTW，这个 presentation 的确讲的非常好，力荐！&lt;/p&gt;
&lt;h2 id="future-and-promise"&gt;Future and Promise&lt;/h2&gt;
&lt;p&gt;标题中的 FPC 指的是 &lt;strong&gt;Future&lt;/strong&gt;、&lt;strong&gt;Promise&lt;/strong&gt; 和 &lt;strong&gt;Continuation&lt;/strong&gt; 这三个概念，这是并发编程中非常常见的一种编程模型；首先不管 Continuation 是什么，先了解 Future 和 Promise；Wikipedia 是这样解释&lt;sup id="fnref:3"&gt;&lt;a href="#fn:3" class="footnote-ref" role="doc-noteref"&gt;3&lt;/a&gt;&lt;/sup&gt;的：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In computer science, &lt;strong&gt;future&lt;/strong&gt;, &lt;strong&gt;promise&lt;/strong&gt;, &lt;strong&gt;delay&lt;/strong&gt;, and &lt;strong&gt;deferred&lt;/strong&gt; refer to constructs used for synchronizing program execution in some concurrent programming languages. They describe an object that acts as a proxy for a result that is initially unknown, usually because the computation of its value is not yet complete.&lt;/p&gt;</description></item></channel></rss>