<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>Inasa - Inasa&#x27;s blog</title>
      <link>https://inasa.dev/posts/</link>
      <description>Stay Hungry Stay Foolish</description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://inasa.dev/posts/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Thu, 07 Aug 2025 00:00:00 +0000</lastBuildDate>
      <item>
          <title>AI | Modelscope接入Claude code</title>
          <pubDate>Thu, 07 Aug 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-08-07-ai-modelscope-ccr/</link>
          <guid>https://inasa.dev/posts/25-08-07-ai-modelscope-ccr/</guid>
          <description xml:base="https://inasa.dev/posts/25-08-07-ai-modelscope-ccr/">&lt;p&gt;除了免费的anyrouter和gemini之外，Modelscope提供每天2000的请求，对于个人来说完全够了。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;bun&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; install&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;g&lt;&#x2F;span&gt; @anthropic-ai&#x2F;claude-code&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;bun&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; install&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;g&lt;&#x2F;span&gt; @musistudio&#x2F;claude-code-router&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;申请魔搭社区的key(https:&#x2F;&#x2F;www.modelscope.cn&#x2F;my&#x2F;myaccesstoken)。&lt;&#x2F;p&gt;
&lt;p&gt;创建配置文件&lt;code&gt;~&#x2F;.claude-code-router&#x2F;config.json&lt;&#x2F;code&gt;：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; class=&quot;language-json z-code&quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Providers&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;    &lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;name&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;modelscope&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;api_base_url&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;https:&#x2F;&#x2F;api-inference.modelscope.cn&#x2F;v1&#x2F;chat&#x2F;completions&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;api_key&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;xxxx&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;models&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Qwen&#x2F;Qwen3-Coder-480B-A35B-Instruct&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;transformer&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;use&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;          &lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-sequence z-begin z-json&quot;&gt;[&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;            &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;maxtoken&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;            &lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;              &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;max_tokens&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-json&quot;&gt;65536&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;            &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;          &lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;          &lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;enhancetool&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;      &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-sequence z-json&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-sequence z-end z-json&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Router&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-begin z-json&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;default&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;modelscope,Qwen&#x2F;Qwen3-Coder-480B-A35B-Instruct&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;HOST&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;127.0.0.1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-pair z-json&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;  &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-key z-json&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;LOG&lt;span class=&quot;z-punctuation z-definition z-string z-end z-json&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-mapping z-key-value z-json&quot;&gt;:&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-constant z-language z-json&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-json&quot;&gt;&lt;span class=&quot;z-meta z-mapping z-value z-json&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-mapping z-end z-json&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;当前也可以是使用ui配饰:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ccr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; ui&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;完成后需要&lt;code&gt;ccr restart&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;开始videcoding:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ccr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; code&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;切换模型,需要使用魔搭社区（https:&#x2F;&#x2F;www.modelscope.cn&#x2F;models）:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&#x2F;model&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; moonshotai&#x2F;Kimi-K2-Instruct&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;linux.do&#x2F;t&#x2F;topic&#x2F;809617&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;github.com&#x2F;musistudio&#x2F;claude-code-router&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;www.modelscope.cn&#x2F;models&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Go | First Response Pattern</title>
          <pubDate>Thu, 07 Aug 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-08-07-go-first-response-pattern/</link>
          <guid>https://inasa.dev/posts/25-08-07-go-first-response-pattern/</guid>
          <description xml:base="https://inasa.dev/posts/25-08-07-go-first-response-pattern/">&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Avoid timeout - Replicate servers and use first response
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Search&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;query&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Result&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;fakeSearch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;kind&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Search&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;query&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Sleep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Duration&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;rand&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Intn&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;100&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Millisecond&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;Result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Sprintf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt; result for &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%q&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;First&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;query&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;replicas&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Search&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;c&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword z-chan z-go&quot;&gt;chan&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;searchReplica&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;replicas&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-go&quot;&gt;range&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;replicas&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;searchReplica&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;start&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Now&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;First&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;golang&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-function z-go&quot;&gt;fakeSearch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;replica1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-function z-go&quot;&gt;fakeSearch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;replica2&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-function z-go&quot;&gt;fakeSearch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;replica3&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;elapsed&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Since&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%.3f&lt;&#x2F;span&gt;ms&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;float64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;elapsed&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Nanoseconds&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-float z-decimal z-go&quot;&gt;1e6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这是 Go 并发经典实践之一：“用副本竞速的方式避免超时，返回最早的可用结果”——常见于高可用分布式系统的请求快速返回（比如多个搜索副本、微服务副本集请谁先响应）。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zhu-yao-si-xiang&quot;&gt;主要思想&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhu-yao-si-xiang&quot; aria-label=&quot;Anchor link for: zhu-yao-si-xiang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;业务背景&lt;&#x2F;strong&gt;：你有好几个“备用服务器&#x2F;副本&#x2F;搜索实现”，哪个响应最快用哪个，“慢的都不用等”，避免整个请求因单点慢或偶发延迟变慢。&lt;&#x2F;li&gt;
&lt;li&gt;这是现实世界中 Google、Amazon 等公司搜索引擎“边缘副本”、“异地容灾高可用”大量使用的技术方案。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;xian-shi-ying-yong-chang-jing&quot;&gt;现实应用场景&lt;a class=&quot;zola-anchor&quot; href=&quot;#xian-shi-ying-yong-chang-jing&quot; aria-label=&quot;Anchor link for: xian-shi-ying-yong-chang-jing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;微服务多活&lt;&#x2F;strong&gt;：多个服务副本响应同一请求，优先拿到第一个并快速返回，极大降低99.99延迟。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;CDN&#x2F;边缘计算&lt;&#x2F;strong&gt;：拉取数据时向多节点并发请求，客户端只拿第一个响应的内容。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;多家供应商比价&#x2F;辅助搜索聚合&lt;&#x2F;strong&gt;：哪个接口快就显示谁的内容。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;shi-yong-contextkong-zhi-goroutine-leak&quot;&gt;使用context控制goroutine leak&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-yong-contextkong-zhi-goroutine-leak&quot; aria-label=&quot;Anchor link for: shi-yong-contextkong-zhi-goroutine-leak&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;这个简单写法确实会导致 goroutine 泄露（goroutine leak）的问题。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;你发起了多个副本 goroutine，每个都会做完自己的“搜索”然后把结果写入同一个 channel &lt;code&gt;c&lt;&#x2F;code&gt;。&lt;&#x2F;li&gt;
&lt;li&gt;但 &lt;code&gt;First&lt;&#x2F;code&gt; 只从 channel 取第一个结果：&lt;code&gt;return &amp;lt;-c&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;其它 goroutine 后续写入 channel 时，如果没人读，&lt;strong&gt;它们会永远阻塞在 &lt;code&gt;c &amp;lt;- ...&lt;&#x2F;code&gt; 这一行上&lt;&#x2F;strong&gt;——此时这些 goroutine 无法退出，即内存泄露。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;First&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;query&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;replicas&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Search&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Result&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;cancel&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;WithCancel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;defer&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;cancel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;c&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword z-chan z-go&quot;&gt;chan&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;searchReplica&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;select&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;case&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;replicas&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;case&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Done&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;			&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-go&quot;&gt;range&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;replicas&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;searchReplica&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-function z-go&quot;&gt;cancel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 让其他 goroutine 自动退出
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;result&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;主流程一旦拿到第一个结果，cancel() 会通知其他所有 goroutine 退出。&lt;&#x2F;p&gt;
&lt;p&gt;复杂情况下可配合 context、WaitGroup 做到无资源泄露。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;www.concurrency.rocks&#x2F;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Android | Pixel 2 XL 设置充电自动开机</title>
          <pubDate>Fri, 01 Aug 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-08-01-pixel-off-mode-charge/</link>
          <guid>https://inasa.dev/posts/25-08-01-pixel-off-mode-charge/</guid>
          <description xml:base="https://inasa.dev/posts/25-08-01-pixel-off-mode-charge/">&lt;h2 id=&quot;shi-yong-fastboot-ming-ling&quot;&gt;使用 fastboot 命令&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-yong-fastboot-ming-ling&quot; aria-label=&quot;Anchor link for: shi-yong-fastboot-ming-ling&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;准备工作&lt;&#x2F;strong&gt;：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;在电脑上安装 ADB 和 Fastboot 工具&lt;&#x2F;li&gt;
&lt;li&gt;在手机上启用开发者选项和 USB 调试&lt;&#x2F;li&gt;
&lt;li&gt;确保手机已解锁 bootloader&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;进入 Fastboot 模式&lt;&#x2F;strong&gt;：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;方法1：使用 ADB 命令&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;powershell&quot; class=&quot;language-powershell z-code&quot;&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;adb reboot bootloader
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;方法2：使用按键组合&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;完全关机&lt;&#x2F;li&gt;
&lt;li&gt;同时按住&lt;strong&gt;电源键 + 音量下键&lt;&#x2F;strong&gt;直到进入 Fastboot 模式&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;执行命令&lt;&#x2F;strong&gt;：
在电脑上执行以下命令：&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;fastboot oem off-mode-charge 0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;默认行为（off-mode-charge = 1）&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;设备关机后插入充电器&lt;&#x2F;li&gt;
&lt;li&gt;设备会显示充电动画&lt;&#x2F;li&gt;
&lt;li&gt;但&lt;strong&gt;不会完全启动&lt;&#x2F;strong&gt;到 Android 系统&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;修改后（off-mode-charge = 0）&lt;&#x2F;strong&gt;
&lt;ul&gt;
&lt;li&gt;设备关机后插入充电器&lt;&#x2F;li&gt;
&lt;li&gt;设备会&lt;strong&gt;自动开机&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;完全启动到 Android 系统&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;重启手机&lt;&#x2F;strong&gt;：&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;fastboot reboot
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;guan-ji-yan-zheng&quot;&gt;关机验证：&lt;a class=&quot;zola-anchor&quot; href=&quot;#guan-ji-yan-zheng&quot; aria-label=&quot;Anchor link for: guan-ji-yan-zheng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;执行&lt;code&gt;adb shell reboot -p&lt;&#x2F;code&gt; 关机&lt;&#x2F;li&gt;
&lt;li&gt;插入充电线，手机应该会自动开机&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;Claude Opus 4&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>C | _Generic泛型选择</title>
          <pubDate>Fri, 25 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-25-c-generic/</link>
          <guid>https://inasa.dev/posts/25-07-25-c-generic/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-25-c-generic/">&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;inasayang.notion.site&#x2F;_Generic-Generic-Selection-23bb97323d23800c8ae7ed3be092827a&quot;&gt;Notion链接&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;_Generic&lt;&#x2F;code&gt; 在 C 语言中被称为&lt;strong&gt;泛型选择&lt;&#x2F;strong&gt;（Generic Selection）或&lt;strong&gt;类型泛型表达式&lt;&#x2F;strong&gt;。这是 C11 标准引入的特性。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;主要用于&lt;strong&gt;类型感知的宏编程&lt;&#x2F;strong&gt;，实现类似函数重载的效果&lt;&#x2F;li&gt;
&lt;li&gt;在&lt;strong&gt;编译时&lt;&#x2F;strong&gt;处理，编译器会直接替换为对应的表达式&lt;&#x2F;li&gt;
&lt;li&gt;基于&lt;strong&gt;类型&lt;&#x2F;strong&gt;进行选择&lt;&#x2F;li&gt;
&lt;li&gt;是一个&lt;strong&gt;表达式&lt;&#x2F;strong&gt;，会被替换为某个值&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;示例：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 编译时根据类型选择
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; i &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;result &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;_Generic&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;i&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;integer&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;float&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;other&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 编译后直接变成：char *result = &amp;quot;integer&amp;quot;;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;_Generic&lt;&#x2F;code&gt; 是一个&lt;strong&gt;表达式&lt;&#x2F;strong&gt;，不是语句，错误示例：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; ❌ 错误！不能写多行代码
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; i &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;result &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;_Generic&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;i&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;It&amp;#39;s an integer&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\\&lt;&#x2F;span&gt;n&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 编译错误
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;integer&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;float&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;other&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;duo-xing-luo-ji-jie-jue-ban-fa&quot;&gt;多行逻辑解决办法&lt;a class=&quot;zola-anchor&quot; href=&quot;#duo-xing-luo-ji-jie-jue-ban-fa&quot; aria-label=&quot;Anchor link for: duo-xing-luo-ji-jie-jue-ban-fa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;1-shi-yong-han-shu-diao-yong&quot;&gt;1. &lt;strong&gt;使用函数调用&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-shi-yong-han-shu-diao-yong&quot; aria-label=&quot;Anchor link for: 1-shi-yong-han-shu-diao-yong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;handle_int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Processing integer&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 可以有复杂逻辑
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;integer&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;handle_float&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Processing float&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;float&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; i &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;result &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;_Generic&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;i&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;handle_int&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;      &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 调用函数
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;handle_float&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;other&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;2-shi-yong-dou-hao-yun-suan-fu&quot;&gt;2. &lt;strong&gt;使用逗号运算符&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-shi-yong-dou-hao-yun-suan-fu&quot; aria-label=&quot;Anchor link for: 2-shi-yong-dou-hao-yun-suan-fu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; i &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;result &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;_Generic&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;i&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;It&amp;#39;s an integer&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;integer&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 逗号运算符
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;It&amp;#39;s a float&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;float&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;other&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;3-jie-he-tiao-jian-biao-da-shi&quot;&gt;3. &lt;strong&gt;结合条件表达式&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-jie-he-tiao-jian-biao-da-shi&quot; aria-label=&quot;Anchor link for: 3-jie-he-tiao-jian-biao-da-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; i &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;result &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;_Generic&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;i&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; i &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;0&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;positive integer&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;non-positive integer&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;float&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;other&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;4-ru-guo-xu-yao-fu-za-luo-ji-jian-yi-yong-hong-bao-zhuang&quot;&gt;4. &lt;strong&gt;如果需要复杂逻辑，建议用宏包装&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-ru-guo-xu-yao-fu-za-luo-ji-jian-yi-yong-hong-bao-zhuang&quot; aria-label=&quot;Anchor link for: 4-ru-guo-xu-yao-fu-za-luo-ji-jian-yi-yong-hong-bao-zhuang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-define z-c&quot;&gt;#define&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-preprocessor z-c&quot;&gt;HANDLE_TYPE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-c&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt; &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;do&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt; \&lt;span class=&quot;z-punctuation z-separator z-continuation z-c&quot;&gt;\&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;result &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;_Generic&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;        &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;handle_int&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;        &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;handle_float&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;other&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; \\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt; \&lt;span class=&quot;z-punctuation z-separator z-continuation z-c&quot;&gt;\&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;    &lt;span class=&quot;z-comment z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;*&lt;&#x2F;span&gt; 在这里可以添加更多处理逻辑 &lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; \&lt;span class=&quot;z-punctuation z-separator z-continuation z-c&quot;&gt;\&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Result: &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; result&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt; \&lt;span class=&quot;z-punctuation z-separator z-continuation z-c&quot;&gt;\&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;while&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 使用
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; i &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;HANDLE_TYPE&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;wan-zheng-shi-li&quot;&gt;完整示例&lt;a class=&quot;zola-anchor&quot; href=&quot;#wan-zheng-shi-li&quot; aria-label=&quot;Anchor link for: wan-zheng-shi-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;h2 id=&quot;shi-li-1&quot;&gt;示例1：&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-li-1&quot; aria-label=&quot;Anchor link for: shi-li-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-include z-c&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-include z-c&quot;&gt;#include&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-other z-lt-gt z-include z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;stdio.h&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-define z-c&quot;&gt;#define&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-preprocessor z-c&quot;&gt;TYPE_NAME&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-c&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;_Generic&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;integer&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;float&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;double&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;character&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;string&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;unknown type&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;void&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; num &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;100&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt; pi &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;3&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;14159&lt;span class=&quot;z-storage z-type z-numeric z-c&quot;&gt;f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt; e &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;2&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;71828&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; letter &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Z&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;message &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;num (&lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%d&lt;&#x2F;span&gt;) is a &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; num&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;TYPE_NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;num&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;pi (&lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%.2f&lt;&#x2F;span&gt;) is a &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; pi&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;TYPE_NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;pi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;e (&lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%.5f&lt;&#x2F;span&gt;) is a &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; e&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;TYPE_NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;letter (&amp;#39;&lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%c&lt;&#x2F;span&gt;&amp;#39;) is a &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; letter&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;TYPE_NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;letter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;message (&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;) is a &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; message&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;TYPE_NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;输出：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;num&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;100&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; is a &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;integer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;pi&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;3&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;14&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; is a &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;e&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;2&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;71828&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt; &lt;&#x2F;span&gt;is a &lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;letter&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Z&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; is a &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;character&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;message&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; is a &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;shi-li-2&quot;&gt;示例2：&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-li-2&quot; aria-label=&quot;Anchor link for: shi-li-2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-include z-c&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-include z-c&quot;&gt;#include&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-other z-lt-gt z-include z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;stdio.h&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-include z-c&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-include z-c&quot;&gt;#include&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-other z-lt-gt z-include z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;math.h&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 为不同类型定义不同的处理函数
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;process_int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-c&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Processing integer: &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; x &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt; x&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 返回平方
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;process_float&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-c&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Processing float: &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;sqrtf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 返回平方根
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;process_double&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-c&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Processing double: &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%.6f&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 返回自然对数
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;process_char&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-c&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Processing character: &amp;#39;&lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%c&lt;&#x2F;span&gt;&amp;#39;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; x&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; x &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;&amp;gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-c&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; x &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;&amp;lt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;z&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;?&lt;&#x2F;span&gt; x &lt;span class=&quot;z-keyword z-operator z-arithmetic z-c&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;32&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; x&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 小写转大写
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;void&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;process_default&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;void&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Processing unsupported type&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 使用 _Generic 创建泛型处理宏
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-define z-c&quot;&gt;#define&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-preprocessor z-c&quot;&gt;PROCESS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-c&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;_Generic&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;    process_int&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;  process_float&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; process_double&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;   process_char&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;:&lt;&#x2F;span&gt; process_default \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 另一个例子：类型泛型的比较函数
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-define z-c&quot;&gt;#define&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-preprocessor z-c&quot;&gt;MAX&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-c&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-c&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;_Generic&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-c&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;b&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;    &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;b&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;b&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;  &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;b&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;b&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;b&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;?&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;b&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;0&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 类型泛型的格式化输出
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-define z-c&quot;&gt;#define&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-preprocessor z-c&quot;&gt;PRINT_VALUE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-c&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;_Generic&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Integer: &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;  &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Float: &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Double: &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%.6f&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;   &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Character: &amp;#39;&lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%c&lt;&#x2F;span&gt;&amp;#39; (ASCII: &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%d&lt;&#x2F;span&gt;)&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;  &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;String: &lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;default&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Unknown type&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; \
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-macro z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;void&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;=== 泛型处理函数示例 ===&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; i &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt; f &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;16&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;0&lt;span class=&quot;z-storage z-type z-numeric z-c&quot;&gt;f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt; d &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;2&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;718281828&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; c &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;h&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Original values:&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PRINT_VALUE&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PRINT_VALUE&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PRINT_VALUE&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PRINT_VALUE&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;Processing results:&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; result_i &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PROCESS&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt; result_f &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PROCESS&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt; result_d &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PROCESS&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; result_c &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PROCESS&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;Processed values:&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PRINT_VALUE&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;result_i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PRINT_VALUE&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;result_f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PRINT_VALUE&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;result_d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PRINT_VALUE&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;result_c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;=== 泛型最大值函数示例 ===&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; max_int &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;MAX&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;25&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt; max_float &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;MAX&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;3&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;14&lt;span class=&quot;z-storage z-type z-numeric z-c&quot;&gt;f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;2&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;71&lt;span class=&quot;z-storage z-type z-numeric z-c&quot;&gt;f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt; max_double &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;MAX&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;1&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;234567&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;1&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;234568&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;MAX(10, 25) = &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; max_int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;MAX(3.14f, 2.71f) = &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%.2f&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; max_float&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;MAX(1.234567, 1.234568) = &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%.6f&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; max_double&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;=== 混合类型示例 ===&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;str &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Hello World&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;long&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-c&quot;&gt;long&lt;&#x2F;span&gt; big_num &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;9876543210&lt;span class=&quot;z-storage z-type z-numeric z-c&quot;&gt;LL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PRINT_VALUE&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;str&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;PRINT_VALUE&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;big_num&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 会触发 default 情况
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;输出：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;==&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; 泛型处理函数示例 &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;==&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Original values&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Integer&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;5&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Float&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;16&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;00&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Double&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;2&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;718282&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Character&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;h&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;ASCII&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;104&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Processing results&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Processing integer&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;5&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Processing &lt;span class=&quot;z-storage z-type z-c&quot;&gt;float&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;16&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;00&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Processing &lt;span class=&quot;z-storage z-type z-c&quot;&gt;double&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;2&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;718282&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Processing character&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;h&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Processed values&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Integer&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;25&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Float&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;4&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;00&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Double&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;1&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;000000&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Character&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;H&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;ASCII&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;72&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;==&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; 泛型最大值函数示例 &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;==&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;MAX&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;25&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;25&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;MAX&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;3&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;14&lt;span class=&quot;z-storage z-type z-numeric z-c&quot;&gt;f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;2&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;71&lt;span class=&quot;z-storage z-type z-numeric z-c&quot;&gt;f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;3&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;14&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;MAX&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;1&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;234567&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;1&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;234568&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-float z-decimal z-c&quot;&gt;1&lt;span class=&quot;z-punctuation z-separator z-decimal z-c&quot;&gt;.&lt;&#x2F;span&gt;234568&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;==&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; 混合类型示例 &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;==&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;String&lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Hello World&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;Unknown &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;en.cppreference.com&#x2F;w&#x2F;c&#x2F;language&#x2F;generic.html&lt;&#x2F;li&gt;
&lt;li&gt;Claude Sonnet 4 Thinking&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Windows | 开启NTP（救火）</title>
          <pubDate>Tue, 15 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-15-windows-ntp/</link>
          <guid>https://inasa.dev/posts/25-07-15-windows-ntp/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-15-windows-ntp/">&lt;p&gt;给我整笑了，让我回去救火...&lt;&#x2F;p&gt;
&lt;p&gt;没有实时数据，只有历史数据。因为写的是InfluxDB。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;windowskai-qi-ntp&quot;&gt;Windows开启NTP&lt;a class=&quot;zola-anchor&quot; href=&quot;#windowskai-qi-ntp&quot; aria-label=&quot;Anchor link for: windowskai-qi-ntp&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;xiu-gai-zhu-ce-biao&quot;&gt;修改注册表&lt;a class=&quot;zola-anchor&quot; href=&quot;#xiu-gai-zhu-ce-biao&quot; aria-label=&quot;Anchor link for: xiu-gai-zhu-ce-biao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;win + R&lt;&#x2F;code&gt; -&amp;gt; &lt;code&gt;regedit&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer&lt;&#x2F;code&gt;，把&lt;code&gt;Enabled&lt;&#x2F;code&gt;设置为&lt;code&gt;1&lt;&#x2F;code&gt;，为打开NTP服务。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config&lt;&#x2F;code&gt;，并把&lt;code&gt;AnnounceFlags&lt;&#x2F;code&gt;的值设置为&lt;code&gt;5&lt;&#x2F;code&gt;（系统默认为&lt;code&gt;a&lt;&#x2F;code&gt;）。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;qi-dong-ntpfu-wu&quot;&gt;启动NTP服务&lt;a class=&quot;zola-anchor&quot; href=&quot;#qi-dong-ntpfu-wu&quot; aria-label=&quot;Anchor link for: qi-dong-ntpfu-wu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;win + R&lt;&#x2F;code&gt; -&amp;gt; &lt;code&gt;services.msc&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;找到&lt;code&gt;Windows Time&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;设置为自动后确定，点击右键重新启动此服务。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;也可以使用命令行来管理&lt;&#x2F;p&gt;
&lt;p&gt;启动：&lt;code&gt;net start w32time&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;停止：&lt;code&gt;net stop w32time&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;ben-ji-ce-shi&quot;&gt;本机测试&lt;a class=&quot;zola-anchor&quot; href=&quot;#ben-ji-ce-shi&quot; aria-label=&quot;Anchor link for: ben-ji-ce-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;powershell输入&lt;code&gt;w32tm &#x2F;stripchart &#x2F;computer:127.0.0.1&lt;&#x2F;code&gt; ，如果有回显则服务正常。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;记得防火墙添加入站规则&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;linuxtong-bu&quot;&gt;Linux同步&lt;a class=&quot;zola-anchor&quot; href=&quot;#linuxtong-bu&quot; aria-label=&quot;Anchor link for: linuxtong-bu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;使用&lt;code&gt;systemd-timesyncd&lt;&#x2F;code&gt;即可，因为自带。离线安装&lt;code&gt;chrony&lt;&#x2F;code&gt;有点儿麻烦。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;systemd-timesyncd&lt;&#x2F;code&gt; 的配置文件通常位于 &lt;code&gt;&#x2F;etc&#x2F;systemd&#x2F;timesyncd.conf&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;[Time]
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# NTP 服务器列表，空格分隔，可以为 IP 或域名
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# 推荐使用公共 NTP 服务器或你组织的授信服务器
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;NTP=ntp.aliyun.com ntp1.aliyun.com time.windows.com
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# 备用服务器（主服务器不可达时自动尝试这些）
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;FallbackNTP=ntp.ubuntu.com ntp.ntsc.ac.cn
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# 是否允许本机成为 NTP 服务器（仅本地局域网用，默认 false）
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# Not allowed with systemd-timesyncd, 该选项 reserved for future
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# PollIntervalMinSec= 最大最小轮询间隔（同步周期），单位秒
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# 通常不用改，特殊需求可设置。举例：最小32秒
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# PollIntervalMinSec=32
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# PollIntervalMaxSec= 最大轮询间隔，举例：2048秒
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# PollIntervalMaxSec=2048
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# RootDistanceMaxSec= 服务器的最大允许误差，超过则不同步，单位秒
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# RootDistanceMaxSec=5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# 操作系统启用&#x2F;禁用NTP守护进程（建议别动，用 timedatectl 控制）。
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# NTP= 的空值表示停用。
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# 对于代理&#x2F;防火墙环境，可通过以下选项设置 NTP 端口
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# ServerPort=123
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;# 可设置的其他参数一般足够，更多参数请看 `man timesyncd.conf`
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;根据情况需要调整RootDistanceMaxSec，否则不同步。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;blockquote&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; restart systemd-timesyncd&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;查看同步状态：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;timedatectl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; status&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;zhuanlan.zhihu.com&#x2F;p&#x2F;453366437&lt;&#x2F;li&gt;
&lt;li&gt;GPT-4.1&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Zig | @branchHint内置函数</title>
          <pubDate>Mon, 14 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-13-zig-branchhint/</link>
          <guid>https://inasa.dev/posts/25-07-13-zig-branchhint/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-13-zig-branchhint/">&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;inasayang.notion.site&#x2F;branchHint-22fb97323d2380e4aed2ddec46077b19&quot;&gt;Notion链接&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&#x2F; This data structure is used by the Zig language code generation and
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&#x2F; therefore must be kept in sync with the compiler implementation.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;pub&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-const z-go&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-declaration z-go&quot;&gt;BranchHint&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;enum&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;u3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&#x2F; Equivalent to no hint given.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;none&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&#x2F; This branch of control flow is more likely to be reached than its peers.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&#x2F; The optimizer should optimize for reaching it.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;likely&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&#x2F; This branch of control flow is less likely to be reached than its peers.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&#x2F; The optimizer should optimize for not reaching it.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;unlikely&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&#x2F; This branch of control flow is unlikely to *ever* be reached.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&#x2F; The optimizer may place it in a different page of memory to optimize other branches.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;cold&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&#x2F; It is difficult to predict whether this branch of control flow will be reached.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&#x2F; The optimizer should avoid branching behavior with expensive mispredictions.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;unpredictable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;none&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;等同于没有给出任何提示。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;likely&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;这个控制流分支比其同级分支更可能被执行到。&lt;&#x2F;li&gt;
&lt;li&gt;优化器应该针对执行到这个分支进行优化。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;unlikely&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;这个控制流分支比其同级分支更不可能被执行到。&lt;&#x2F;li&gt;
&lt;li&gt;优化器应该针对不执行到这个分支进行优化。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;cold&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;这个控制流分支几乎不可能被执行到。&lt;&#x2F;li&gt;
&lt;li&gt;优化器可能将其放置在不同的内存页面中，以优化其他分支。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;unpredictable&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;很难预测这个控制流分支是否会被执行到。&lt;&#x2F;li&gt;
&lt;li&gt;优化器应该避免具有昂贵误预测代价的分支行为。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;none-wu-ti-shi&quot;&gt;&lt;code&gt;none&lt;&#x2F;code&gt; - 无提示&lt;a class=&quot;zola-anchor&quot; href=&quot;#none-wu-ti-shi&quot; aria-label=&quot;Anchor link for: none-wu-ti-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;&#x2F; 编译器自行决定优化策略
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;if (condition) {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &#x2F;&#x2F; 没有特殊优化提示
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;likely-hen-ke-neng-zhi-xing&quot;&gt;&lt;code&gt;likely&lt;&#x2F;code&gt; - 很可能执行&lt;a class=&quot;zola-anchor&quot; href=&quot;#likely-hen-ke-neng-zhi-xing&quot; aria-label=&quot;Anchor link for: likely-hen-ke-neng-zhi-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;&#x2F; 告诉编译器这个分支很可能被执行
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;if (@branch(.likely, hot_path_condition)) {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &#x2F;&#x2F; 这里的代码会被优化器重点关注
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    frequently_executed_code();
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;unlikely-bu-tai-ke-neng-zhi-xing&quot;&gt;&lt;code&gt;unlikely&lt;&#x2F;code&gt; - 不太可能执行&lt;a class=&quot;zola-anchor&quot; href=&quot;#unlikely-bu-tai-ke-neng-zhi-xing&quot; aria-label=&quot;Anchor link for: unlikely-bu-tai-ke-neng-zhi-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;&#x2F; 告诉编译器这个分支不太可能被执行
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;if (@branch(.unlikely, error_condition)) {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &#x2F;&#x2F; 错误处理代码，不会被高度优化
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    handle_error();
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;cold-ji-hu-bu-hui-zhi-xing&quot;&gt;&lt;code&gt;cold&lt;&#x2F;code&gt; - 几乎不会执行&lt;a class=&quot;zola-anchor&quot; href=&quot;#cold-ji-hu-bu-hui-zhi-xing&quot; aria-label=&quot;Anchor link for: cold-ji-hu-bu-hui-zhi-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;&#x2F; 极少执行的代码路径
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;if (@branch(.cold, rare_debug_condition)) {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &#x2F;&#x2F; 这部分代码可能被放到内存的远端位置
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    debug_panic(&amp;quot;This should never happen&amp;quot;);
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;unpredictable-nan-yi-yu-ce&quot;&gt;&lt;code&gt;unpredictable&lt;&#x2F;code&gt; - 难以预测&lt;a class=&quot;zola-anchor&quot; href=&quot;#unpredictable-nan-yi-yu-ce&quot; aria-label=&quot;Anchor link for: unpredictable-nan-yi-yu-ce&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;&#x2F; 随机或高度动态的分支
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;if (@branch(.unpredictable, random_condition)) {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &#x2F;&#x2F; 编译器会避免激进的分支预测优化
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    random_behavior();
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;bian-yi-qi-you-hua-ying-xiang&quot;&gt;&lt;strong&gt;编译器优化影响&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#bian-yi-qi-you-hua-ying-xiang&quot; aria-label=&quot;Anchor link for: bian-yi-qi-you-hua-ying-xiang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;提示类型&lt;&#x2F;th&gt;&lt;th&gt;优化策略&lt;&#x2F;th&gt;&lt;th&gt;内存布局&lt;&#x2F;th&gt;&lt;th&gt;预测策略&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;likely&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;高优先级优化&lt;&#x2F;td&gt;&lt;td&gt;放在热点代码附近&lt;&#x2F;td&gt;&lt;td&gt;假设会执行&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;unlikely&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;低优先级优化&lt;&#x2F;td&gt;&lt;td&gt;正常布局&lt;&#x2F;td&gt;&lt;td&gt;假设不会执行&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;cold&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;最低优先级&lt;&#x2F;td&gt;&lt;td&gt;可能放到远端内存页&lt;&#x2F;td&gt;&lt;td&gt;强烈假设不执行&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;unpredictable&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;保守优化&lt;&#x2F;td&gt;&lt;td&gt;正常布局&lt;&#x2F;td&gt;&lt;td&gt;避免激进预测&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;shi-li&quot;&gt;示例&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-li&quot; aria-label=&quot;Anchor link for: shi-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-const z-go&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-declaration z-go&quot;&gt;std&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; @&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;std&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-const z-go&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-declaration z-go&quot;&gt;BranchHint&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;std&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;builtin&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;BranchHint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 简单完整的例子：处理用户输入
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;fn&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;processInput&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;void&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;std&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Processing value: {}&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 1. likely - 大部分输入都是正数且在合理范围内
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;and&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        @&lt;span class=&quot;z-variable z-function z-go&quot;&gt;branchHint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;likely&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;std&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;✓ Normal positive value (likely)&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 2. unpredictable - 奇偶性无法预测
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;@&lt;span class=&quot;z-variable z-function z-go&quot;&gt;rem&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            @&lt;span class=&quot;z-variable z-function z-go&quot;&gt;branchHint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;unpredictable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-variable z-other z-go&quot;&gt;std&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;  → Even number (unpredictable)&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;else&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            @&lt;span class=&quot;z-variable z-function z-go&quot;&gt;branchHint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;unpredictable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-variable z-other z-go&quot;&gt;std&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;  → Odd number (unpredictable)&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 3. unlikely - 负数输入较少发生
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        @&lt;span class=&quot;z-variable z-function z-go&quot;&gt;branchHint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;unlikely&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;std&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;⚠ Negative value (unlikely)&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 4. cold - 极大值几乎不会出现，可能是错误或攻击
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1000000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        @&lt;span class=&quot;z-variable z-function z-go&quot;&gt;branchHint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;cold&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;std&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;🚨 Extremely large value detected! (cold)&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 5. unlikely - 0和中等大小的值不常见
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        @&lt;span class=&quot;z-variable z-function z-go&quot;&gt;branchHint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;unlikely&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;std&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;⚠ Zero value (unlikely)&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;else&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        @&lt;span class=&quot;z-variable z-function z-go&quot;&gt;branchHint&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;unlikely&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;std&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;⚠ Medium large value: {} (unlikely)&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;pub&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fn&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;void&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;std&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;=== Branch Hint Demo ===&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 测试所有分支类型
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-storage z-type z-keyword z-const z-go&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-declaration z-go&quot;&gt;test_values&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;42&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; likely: 正常正数
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;123&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; likely: 正常正数
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; unlikely: 负数
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; unlikely: 零
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;5000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; unlikely: 中等大值
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;2000000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; cold: 极大值
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;17&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; likely: 正常正数
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;100&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; unlikely: 负数
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;test_values&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-function z-go&quot;&gt;processInput&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;std&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;debug&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;Claude Sonnet 4 Thinking&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;ziggit.dev&#x2F;t&#x2F;about-branchhint&#x2F;7408&#x2F;6&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;github.com&#x2F;ziglang&#x2F;zig&#x2F;issues&#x2F;21148&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;ziglang.org&#x2F;documentation&#x2F;master&#x2F;#branchHint&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;github.com&#x2F;ziglang&#x2F;zig&#x2F;blob&#x2F;master&#x2F;lib&#x2F;std&#x2F;builtin.zig#L981&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Go | （类型）集合的乐趣</title>
          <pubDate>Sun, 13 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-13-go-the-joy-of-type-sets/</link>
          <guid>https://inasa.dev/posts/25-07-13-go-the-joy-of-type-sets/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-13-go-the-joy-of-type-sets/">&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;inasayang.notion.site&#x2F;22fb97323d2380e68820d2f9fa84ef91&quot;&gt;Notion链接&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;💡&lt;em&gt;A set is a Many that allows itself to be &amp;gt;&amp;gt;thought of as a One.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;—Georg Cantor, quoted in Rudy Rucker’s &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;amzn.to&#x2F;3viu3v8&quot;&gt;“Infinity and the Mind”&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;泛型编程的要点是能够编写操作多于一种具体数据类型的代码。这样一来，我们就不必重复编写相同的代码，一遍又一遍，为每种需要处理的数据类型各写一份代码。&lt;&#x2F;p&gt;
&lt;p&gt;但是对数据类型过于自由和宽松也会走得太远：接受字面上任何类型数据的类型参数并不太有用。我们需要约束（constraints）来缩小一个函数能处理的类型集合。当类型集合是无限的（例如 [T any]），我们几乎无法对这些值做任何事情，因为我们对它们一无所知。&lt;&#x2F;p&gt;
&lt;p&gt;那么，我们如何编写更灵活的约束，使得它们所包含的类型集合既足够广泛以实用，又足够狭窄以便可用呢？&lt;&#x2F;p&gt;
&lt;p&gt;我们已经知道，一种接口可以通过列出方法元素（method elements）来指定允许的类型范围，比如 &lt;code&gt;String()&lt;&#x2F;code&gt; 这个字符串方法。我们将使用“基本接口”（basic interface）一词来描述只包含方法元素的接口，但现在让我们引入另一种接口。它不是列出类型必须拥有的方法，而是直接指定允许的类型集合。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;lei-xing-yuan-su&quot;&gt;&lt;strong&gt;类型元素&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#lei-xing-yuan-su&quot; aria-label=&quot;Anchor link for: lei-xing-yuan-su&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;例如，假设我们想写一个泛型函数 Double，将一个数字乘以二，并且我们想要一个类型约束，只允许 int 类型的值。我们知道 int 没有任何方法，所以不能用任何基本接口作为约束。那么我们该如何写呢？&lt;&#x2F;p&gt;
&lt;p&gt;好吧，方法如下：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;OnlyInt&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;非常直接！它看起来就像一个普通的接口定义，只不过不是包含方法元素，而是包含一个类型元素（type element），由一个命名类型组成。在这个例子中，这个命名类型是 int。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;shi-yong-lei-xing-ji-he-yue-shu&quot;&gt;使用类型集合约束&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-yong-lei-xing-ji-he-yue-shu&quot; aria-label=&quot;Anchor link for: shi-yong-lei-xing-ji-he-yue-shu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;我们如何使用这样的约束呢？那我们来写一个 Double 函数：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Double&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;OnlyInt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;v&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;v&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;换句话说，对于满足 OnlyInt 约束的某个类型 T，Double 接受一个 T 类型的参数并返回一个 T 类型的结果。&lt;&#x2F;p&gt;
&lt;p&gt;注意，我们现在有了一个解决方案，针对之前尝试编写 AddAnything 函数时遇到的问题：如何在参数化函数中启用 &lt;code&gt;*&lt;&#x2F;code&gt; 运算符（或其他算术运算符）。由于 T 只能是 int（得益于 OnlyInt 约束），Go 可以保证 &lt;code&gt;*&lt;&#x2F;code&gt; 运算符能用于 T 类型的值。&lt;&#x2F;p&gt;
&lt;p&gt;不过，这还不是完整的答案，因为还有其他支持 &lt;code&gt;*&lt;&#x2F;code&gt; 运算符的类型，它们不会被此约束允许。而且，如果我们只打算支持 int，也完全可以写一个接受 int 参数的普通函数。&lt;&#x2F;p&gt;
&lt;p&gt;因此，我们需要能够稍微扩大约束允许的类型范围，但不能超出支持 &lt;code&gt;*&lt;&#x2F;code&gt; 运算符的类型。我们该如何做到这点呢？&lt;&#x2F;p&gt;
&lt;h1 id=&quot;lian-he-lei-xing&quot;&gt;联合类型&lt;a class=&quot;zola-anchor&quot; href=&quot;#lian-he-lei-xing&quot; aria-label=&quot;Anchor link for: lian-he-lei-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;哪些类型能满足约束 OnlyInt？答案是，只有 int！为了扩大这个范围，我们可以创建一个指定多个命名类型的约束：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Integer&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;int8&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;int16&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;int32&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这些类型由管道符号（&lt;code&gt;|&lt;&#x2F;code&gt;）分隔。你可以把它理解为表示“或”的关系。换句话说，如果一个类型是 int 或 int8 或……，那么它就满足这个约束。&lt;&#x2F;p&gt;
&lt;p&gt;这种接口元素称为联合（union）。联合中的类型元素可以包含任意 Go 类型，包括接口类型。&lt;&#x2F;p&gt;
&lt;p&gt;它甚至可以包含其他约束。换言之，我们可以从已有的约束组合（compose）出新的约束，比如：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Float&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;float32&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;float64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Complex&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;complex64&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;complex128&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Number&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Integer&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Float&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;Complex&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;我们说 Integer、Float 和 Complex 都是不同内置数值类型的联合，同时我们也创建了一个新的约束 Number，它是这三个接口类型的联合。只要是整数、浮点数或复数，那它就是一个数字！&lt;&#x2F;p&gt;
&lt;h1 id=&quot;suo-you-yun-xu-lei-xing-de-ji-he&quot;&gt;所有允许类型的集合&lt;a class=&quot;zola-anchor&quot; href=&quot;#suo-you-yun-xu-lei-xing-de-ji-he&quot; aria-label=&quot;Anchor link for: suo-you-yun-xu-lei-xing-de-ji-he&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;约束的类型集合（type set）是满足该约束的所有类型的集合。空接口（any）的类型集合就是所有类型的集合，正如你所预期的那样。&lt;&#x2F;p&gt;
&lt;p&gt;联合元素（例如前面例子中的 Float）的类型集合是其所有成员类型集合的联合。&lt;&#x2F;p&gt;
&lt;p&gt;在 Float 例子中，它是 &lt;code&gt;float32 | float64&lt;&#x2F;code&gt; 的联合，其类型集合包含 &lt;code&gt;float32&lt;&#x2F;code&gt;、&lt;code&gt;float64&lt;&#x2F;code&gt;，且不包含其他类型。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;jiao-ji&quot;&gt;交集&lt;a class=&quot;zola-anchor&quot; href=&quot;#jiao-ji&quot; aria-label=&quot;Anchor link for: jiao-ji&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;你可能知道，对于一个基本接口，一个类型必须实现该接口中列出的所有方法。如果接口中包含其他接口，一个类型必须实现所有这些接口，而不仅仅是其中一个。&lt;&#x2F;p&gt;
&lt;p&gt;例如：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;ReaderStringer&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;io&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;Reader&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;Stringer&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;如果我们把它写成接口字面量（interface literal），方法之间用分号隔开，而不是换行，但含义一样：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;io&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;Reader&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;Stringer&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;要实现这个接口，类型必须同时实现 io.Reader 和 fmt.Stringer，单独实现其中一个是不够的。&lt;&#x2F;p&gt;
&lt;p&gt;接口定义中的每一行都被视为一个独立的类型元素。接口的类型集合是所有元素类型集合的交集。也就是说，只有那些所有元素都共有的类型才属于该接口的类型集合。&lt;&#x2F;p&gt;
&lt;p&gt;因此，将接口元素写在不同的行上，实际上要求类型必须实现所有这些元素。我们不常用这种接口，但可以想象某些场景中它是必要的。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;kong-lei-xing-ji-he&quot;&gt;空类型集合&lt;a class=&quot;zola-anchor&quot; href=&quot;#kong-lei-xing-ji-he&quot; aria-label=&quot;Anchor link for: kong-lei-xing-ji-he&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;你可能会想，如果我们定义了一个类型集合完全为空的接口会发生什么。也就是说，没有任何类型能满足该约束。&lt;&#x2F;p&gt;
&lt;p&gt;这种情况确实有可能发生，比如两个类型集合做交集，但它们没有任何共同元素。例如：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Unpossible&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;显然，没有任何类型可以同时是 int 和 string！换句话说，这个接口的类型集合是空的。&lt;&#x2F;p&gt;
&lt;p&gt;如果我们尝试实例化一个受 Unpossible 约束限制的函数，自然会发现无法完成：&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cannot implement Unpossible (empty type set)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;我们大概不会故意这么做，因为无法满足的约束似乎没什么用。但在更复杂的接口中，我们可能无意中将允许的类型集合缩减到零，这时了解这个错误信息的含义有助于我们解决问题。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;fu-he-lei-xing-zi-mian-liang&quot;&gt;复合类型字面量&lt;a class=&quot;zola-anchor&quot; href=&quot;#fu-he-lei-xing-zi-mian-liang&quot; aria-label=&quot;Anchor link for: fu-he-lei-xing-zi-mian-liang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;复合类型是由其他类型构建而成的类型。我们在之前的教程中见过一些复合类型，比如 &lt;code&gt;[]E&lt;&#x2F;code&gt;，它是元素类型为 E 的切片。&lt;&#x2F;p&gt;
&lt;p&gt;但我们不仅限于带有名称的已定义类型。我们也可以使用类型字面量（type literal）动态构造新类型：即直接把类型定义写成接口的一部分。&lt;&#x2F;p&gt;
&lt;p&gt;举个例子，这个接口指定了一个 struct 类型字面量：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Pointish&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;X&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;Y&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;具有此约束的类型参数允许任何该结构体的实例。换句话说，其类型集合正好包含一个类型：&lt;code&gt;struct{ X, Y int }&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;fang-wen-jie-gou-ti-zi-duan&quot;&gt;访问结构体字段&lt;a class=&quot;zola-anchor&quot; href=&quot;#fang-wen-jie-gou-ti-zi-duan&quot; aria-label=&quot;Anchor link for: fang-wen-jie-gou-ti-zi-duan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;虽然我们可以编写受某些结构体类型（如 Pointish）约束的泛型函数，但该函数对该类型能做的事情存在限制。其中之一是它无法访问结构体的字段：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;GetX&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Pointish&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;X&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; p.X 未定义（类型 T 没有字段或方法 X）
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;换句话说，我们无法访问参数 p 的字段，尽管函数的约束明确说明任何 p 都保证是至少包含字段 X 的结构体。这是 Go 编译器的一个限制，目前尚未解决。对此表示抱歉。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;lei-xing-ji-he-de-yi-xie-xian-zhi&quot;&gt;类型集合的一些限制&lt;a class=&quot;zola-anchor&quot; href=&quot;#lei-xing-ji-he-de-yi-xie-xian-zhi&quot; aria-label=&quot;Anchor link for: lei-xing-ji-he-de-yi-xie-xian-zhi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;包含类型元素的接口只能用作类型参数的约束。它不能像基本接口那样，用作变量或参数声明的类型。这一点未来可能会有所改变，但目前情况就是这样。&lt;&#x2F;p&gt;
&lt;p&gt;那么，究竟是什么阻止了我们这样做呢？我们已经知道可以编写接受一些基本接口类型（如 Stringer）作为普通参数的函数。那么如果尝试用包含类型元素的接口（例如 Number）做同样的事情，会发生什么呢？&lt;&#x2F;p&gt;
&lt;p&gt;来看一个例子：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Double&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;p&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Number&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Number&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; interface contains type constraints
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这段代码无法编译，原因正如我们之前讨论的。这里可能产生一些混淆：基本接口既可以用作普通接口类型，也可以用作类型参数的约束；但包含类型元素的接口只能用作约束，不能用作普通接口类型。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基本接口（basic interface）&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;指的是不包含类型元素（type elements）的接口，比如：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Stringer&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;接口中的类型元素（type elements）&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;是 Go 1.18 及以后版本引入的机制，允许接口表达类型约束，例如：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Number&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;float64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这是一个类型集合，表示所有满足约束的类型。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;1-ji-ben-jie-kou-ke-yi-shuang-zhong-shen-fen-jie-kou-lei-xing-he-yue-shu&quot;&gt;1. 基本接口可以双重身份：接口类型和约束&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-ji-ben-jie-kou-ke-yi-shuang-zhong-shen-fen-jie-kou-lei-xing-he-yue-shu&quot; aria-label=&quot;Anchor link for: 1-ji-ben-jie-kou-ke-yi-shuang-zhong-shen-fen-jie-kou-lei-xing-he-yue-shu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;基础接口具有双重身份：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;接口类型&lt;&#x2F;strong&gt;：可以用来声明变量、函数参数或返回值的具体类型。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;PrintString&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;s&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Stringer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;类型约束&lt;&#x2F;strong&gt;：也可以用于泛型类型参数约束，告诉编译器此泛型参数需要满足某个接口。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;PrintAll&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Stringer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;items&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;item&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-go&quot;&gt;range&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;items&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;item&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;这里，&lt;code&gt;Stringer&lt;&#x2F;code&gt; 既是一个接口类型（能用作变量或参数类型），又是一个类型约束（能用于泛型约束）。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-han-you-lei-xing-yuan-su-de-jie-kou-zhi-neng-yong-zuo-yue-shu-bu-neng-zuo-wei-pu-tong-jie-kou-lei-xing&quot;&gt;2. 含有类型元素的接口只能用作约束，&lt;strong&gt;不能&lt;&#x2F;strong&gt;作为普通接口类型&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-han-you-lei-xing-yuan-su-de-jie-kou-zhi-neng-yong-zuo-yue-shu-bu-neng-zuo-wei-pu-tong-jie-kou-lei-xing&quot; aria-label=&quot;Anchor link for: 2-han-you-lei-xing-yuan-su-de-jie-kou-zhi-neng-yong-zuo-yue-shu-bu-neng-zuo-wei-pu-tong-jie-kou-lei-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;接口如果包含类型元素（类型集合）， 就只能作为&lt;strong&gt;类型参数的约束&lt;&#x2F;strong&gt;，不能用作普通接口类型进行变量声明或函数参数传递。&lt;&#x2F;p&gt;
&lt;p&gt;原因如下：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;接口表示“类型集合”而非单一类型&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;基本接口定义的是一组类型应该实现哪些方法（行为），所以它是一个类型描述，可以对应一个动态类型的接口值；&lt;&#x2F;p&gt;
&lt;p&gt;而含有类型元素的接口，是描述一个“集合类型”，例如：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Number&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;float64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这意味着 &lt;code&gt;Number&lt;&#x2F;code&gt; 表示两种不同类型的集合——&lt;code&gt;int&lt;&#x2F;code&gt; 和 &lt;code&gt;float64&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;这不是一个具体的类型，而是一个编译期的类型&lt;strong&gt;约束&lt;&#x2F;strong&gt;。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;运行时无法表示这种集合类型&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;在 Go 语言的运行时，接口类型变量有一个具体的实现类型和值；但是集合类型描述的是一个范围、一组类型，而不是单一的动态类型。这使得所谓的“Number 类型变量”在运行时是不明确或不存在的。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;编译器限制&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;因此，Go 编译器拒绝将带有类型元素的接口用作普通接口类型，即不能像基本接口那样声明变量或函数参数。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;3-ju-ti-dui-bi-shi-li&quot;&gt;3. 具体对比示例&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-ju-ti-dui-bi-shi-li&quot; aria-label=&quot;Anchor link for: 3-ju-ti-dui-bi-shi-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 基本接口，可以当作类型使用
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Stringer&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;PrintString&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;s&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Stringer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 含类型元素的接口，只能用作约束
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Number&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;float64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 不能这样用（会报错）
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Double&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Number&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Number&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 编译失败，类型 Number 不能用作参数类型
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 正确的用法，作为类型参数约束
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;DoubleGeneric&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Number&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;zong-jie&quot;&gt;总结&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;接口类型&lt;&#x2F;th&gt;&lt;th&gt;用作变量&#x2F;参数类型（变量声明）&lt;&#x2F;th&gt;&lt;th&gt;用作泛型约束（类型参数约束）&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;基本接口&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;支持&lt;&#x2F;td&gt;&lt;td&gt;支持&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;含类型元素的接口&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;不支持&lt;&#x2F;td&gt;&lt;td&gt;支持&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h1 id=&quot;yue-shu-bu-shi-lei&quot;&gt;约束不是类&lt;a class=&quot;zola-anchor&quot; href=&quot;#yue-shu-bu-shi-lei&quot; aria-label=&quot;Anchor link for: yue-shu-bu-shi-lei&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;如果你有一些使用类（类指类型的层级体系）的语言经验，那么在 Go 泛型中有一点可能会让你困惑：约束并不是类，你不能基于约束接口实例化泛型函数或类型。&lt;&#x2F;p&gt;
&lt;p&gt;举例来说，假设我们有两个具体类型 Cow 和 Chicken：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Cow&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;moo&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Chicken&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;cluck&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;然后假设我们定义了一个接口 Animal，它的类型集合由 Cow 和 Chicken 组成：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Animal&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Cow&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;Chicken&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;到目前为止，一切都很好。现在假设我们定义了一个泛型类型 Farm，它是类型参数 T Animal 的切片：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Farm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Animal&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;T&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;由于我们知道 Animal 的类型集合包含且仅包含 Cow 和 Chicken，那么这两种类型中的任何一个都可以用来实例化 Farm：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;dairy&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Farm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Cow&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;poultry&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Farm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Chicken&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;那 Animal 本身怎么样呢？我们可以创建一个 Farm[Animal] 吗？不可以，因为不存在 Animal 这样一个类型。它是类型约束，而不是类型，所以会报错：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;mixed&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Farm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Animal&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; interface contains type constraints
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;正如我们看到的，我们也不能将 Animal 用作某个变量的类型，或者普通函数的参数类型。只有基本接口可以这样使用，包含类型元素的接口不行。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;GPT-4.1 mini&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;bitfieldconsulting.com&#x2F;posts&#x2F;type-sets&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Zig | 使用zig版本管理器</title>
          <pubDate>Sun, 13 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-13-zig-version-manager/</link>
          <guid>https://inasa.dev/posts/25-07-13-zig-version-manager/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-13-zig-version-manager/">&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;inasayang.notion.site&#x2F;zig-22fb97323d238052a39aeadefe0cfa0c&quot;&gt;Notion链接&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;版本管理器：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;github.com&#x2F;marler8997&#x2F;anyzig&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;github.com&#x2F;asdf-vm&#x2F;asdf&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;由于&lt;code&gt;asdf&lt;&#x2F;code&gt;没有&lt;code&gt;windows&lt;&#x2F;code&gt;版本，所以这里使用&lt;code&gt;anyzig&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;guan-fang-jie-shi&quot;&gt;官方解释&lt;a class=&quot;zola-anchor&quot; href=&quot;#guan-fang-jie-shi&quot; aria-label=&quot;Anchor link for: guan-fang-jie-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;一个通用的 Zig 可执行文件，允许你运行任何版本的 Zig。由于你的 &lt;code&gt;PATH&lt;&#x2F;code&gt; 中只能有一个 &lt;code&gt;zig&lt;&#x2F;code&gt; 可执行文件，anyzig 解决了只能使用一个版本的限制。调用的 Zig 版本是从 &lt;code&gt;build.zig.zon&lt;&#x2F;code&gt; 文件中的 &lt;code&gt;minimum_zig_version&lt;&#x2F;code&gt; 字段读取的。&lt;code&gt;build.zig.zon&lt;&#x2F;code&gt; 文件通过搜索当前目录或任意父目录来定位。&lt;&#x2F;p&gt;
&lt;p&gt;每当需要新的 Zig 版本时，anyzig 会调用等同于 &lt;code&gt;zig fetch ZIG_DOWNLOAD_URL&lt;&#x2F;code&gt; 的命令，将对应版本下载到全局缓存中。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; zig 0.13.0 build-exe myproject.zig&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; zig 0.14.0-dev.3028+cdc9d65b0 build-exe mynewerproject.zig&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;anyzig 还添加了一些自定义命令，可以通过 &lt;code&gt;zig any ...&lt;&#x2F;code&gt; 查询和调用。&lt;&#x2F;p&gt;
&lt;p&gt;Mach 是一个游戏引擎，提供了一个镜像用于下载 Zig 编译器以及它自己“指定版本”（nominated versions）。https:&#x2F;&#x2F;machengine.org&#x2F;docs&#x2F;nominated-zig&#x2F;&lt;&#x2F;p&gt;
&lt;p&gt;Mach 的版本格式不同（例如 &lt;code&gt;2024.10.0-mach&lt;&#x2F;code&gt;），且版本号总是以 &lt;code&gt;-mach&lt;&#x2F;code&gt; 结尾。因此，如果 anyzig 发现一个类似的版本号，它就会知道这是一个 Mach 版本，需要通过 Mach 的下载索引来解析成实际的下载 URL。&lt;&#x2F;p&gt;
&lt;p&gt;💡&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Mach 是一个游戏引擎项目。它需要使用特定版本的 Zig 编译器来构建。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;为了方便使用，Mach 自己维护了一个专门的 Zig 编译器下载镜像（就是它提供的一个服务器，里面存放了很多 Zig 编译器版本供下载）。&lt;&#x2F;li&gt;
&lt;li&gt;这些 Zig 编译器版本是 Mach 特别“指定”的版本，称为“nominated versions”（指定版本），它们可能和官方 Zig 编译器的普通版本不太一样。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Mach 版本的 Zig 编译器版本号格式和官方 Zig 版本号不一样，比如形如：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;2024.10.0-mach&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这个版本号&lt;strong&gt;总是以 &lt;code&gt;-mach&lt;&#x2F;code&gt; 结尾&lt;&#x2F;strong&gt;，这表示它是 Mach 专门做的版本，而不是 Zig 官方的普通版本。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;anyzig 还会检查你 &lt;code&gt;build.zig.zon&lt;&#x2F;code&gt; 文件中的 &lt;code&gt;.mach_zig_version = &quot;...&quot;&lt;&#x2F;code&gt; 属性，并优先使用这个属性替代 &lt;code&gt;.minimum_zig_version&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;使用 &lt;code&gt;.mach_zig_version&lt;&#x2F;code&gt; 替代 &lt;code&gt;.minimum_zig_version&lt;&#x2F;code&gt; 的原因是：未来 Zig 可能会对 &lt;code&gt;minimum_zig_version&lt;&#x2F;code&gt; 字段做一些验证，而使用 Mach 版本时，这个验证很可能会失败，因此用 &lt;code&gt;.mach_zig_version&lt;&#x2F;code&gt; 来避免这个问题。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;an-zhuang-ce-shi&quot;&gt;安装测试&lt;a class=&quot;zola-anchor&quot; href=&quot;#an-zhuang-ce-shi&quot; aria-label=&quot;Anchor link for: an-zhuang-ce-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;下载解压后，添加到环境变量。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;chu-shi-hua-xiang-mu&quot;&gt;初始化项目&lt;a class=&quot;zola-anchor&quot; href=&quot;#chu-shi-hua-xiang-mu&quot; aria-label=&quot;Anchor link for: chu-shi-hua-xiang-mu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;需要指定版本&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;❯&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; zig 0.14.1 init&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;anyzig:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; appdata &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;C:\Users\{username}\AppData\Local\anyzig&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;anyzig:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; zig &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;0.14.1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; already exists at &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;C:\Users\{username}\AppData\Local\zig\p\N-V-__8AADFbwBIm9-O6Nm2fcNyYCR1DpSNvEl8Y_YOVvaHg&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;info:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; created build.zig&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;info:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; created build.zig.zon&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;info:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; created src&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\m&lt;&#x2F;span&gt;ain.zig&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;info:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; created src&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\r&lt;&#x2F;span&gt;oot.zig&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;info:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; see &lt;span class=&quot;z-meta z-group z-expansion z-command z-backticks z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-shell&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;help&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-shell&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; for a menu of options&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;anyzig:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; C:&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\U&lt;&#x2F;span&gt;sers&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\{&lt;&#x2F;span&gt;username&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;}&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\D&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;esktop&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\z&lt;&#x2F;span&gt;ig-pro&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\b&lt;&#x2F;span&gt;uild.zig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;zhi-xing-run&quot;&gt;执行run&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhi-xing-run&quot; aria-label=&quot;Anchor link for: zhi-xing-run&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;❯&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; zig run .&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\s&lt;&#x2F;span&gt;rc&lt;span class=&quot;z-constant z-character z-escape z-shell&quot;&gt;\m&lt;&#x2F;span&gt;ain.zig&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;anyzig:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; zig version &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;0.14.1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; pulled from &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;C:\Users\{username}\Desktop\zig-pro\build.zig.zon&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;anyzig:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; appdata &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;C:\Users\{username}\AppData\Local\anyzig&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;anyzig:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; zig &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;0.14.1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; already exists at &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;C:\Users\{username}\AppData\Local\zig\p\N-V-__8AADFbwBIm9-O6Nm2fcNyYCR1DpSNvEl8Y_YOVvaHg&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;All&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; your codebase are belong to us.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-meta z-group z-expansion z-command z-backticks z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-shell&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;zig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build test&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-shell&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; to run the tests.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</description>
      </item>
      <item>
          <title>Go | 非导出字段反射访问</title>
          <pubDate>Sat, 12 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-12-go-access-private-field/</link>
          <guid>https://inasa.dev/posts/25-07-12-go-access-private-field/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-12-go-access-private-field/">&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;inasayang.notion.site&#x2F;1b3b97323d2380aa964ae8ce07b22860&quot;&gt;Notion链接&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;背景：由于调试需要，需要获取&lt;code&gt;scheduler&lt;&#x2F;code&gt;结构体中的&lt;code&gt;started&lt;&#x2F;code&gt;字段。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Scheduler&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Jobs returns all the jobs currently in the scheduler.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Jobs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Job&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; NewJob creates a new job in the Scheduler. The job is scheduled per the provided
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; definition when the Scheduler is started. If the Scheduler is already running
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; the job will be scheduled when the Scheduler is started.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;NewJob&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;JobDefinition&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Task&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;JobOption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Job&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; RemoveByTags removes all jobs that have at least one of the provided tags.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;RemoveByTags&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; RemoveJob removes the job with the provided id.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;RemoveJob&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;uuid&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;UUID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Shutdown should be called when you no longer need
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; the Scheduler or Job&amp;#39;s as the Scheduler cannot
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; be restarted after calling Shutdown. This is similar
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; to a Close or Cleanup method and is often deferred after
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; starting the scheduler.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Shutdown&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Start begins scheduling jobs for execution based
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; on each job&amp;#39;s definition. Job&amp;#39;s added to an already
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; running scheduler will be scheduled immediately based
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; on definition. Start is non-blocking.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; StopJobs stops the execution of all jobs in the scheduler.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; This can be useful in situations where jobs need to be
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; paused globally and then restarted with Start().
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;StopJobs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Update replaces the existing Job&amp;#39;s JobDefinition with the provided
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; JobDefinition. The Job&amp;#39;s Job.ID() remains the same.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Update&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;uuid&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;UUID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;JobDefinition&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Task&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;JobOption&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Job&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; JobsWaitingInQueue number of jobs waiting in Queue in case of LimitModeWait
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; In case of LimitModeReschedule or no limit it will be always zero
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;JobsWaitingInQueue&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;scheduler&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; context used for shutting down
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;shutdownCtx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; cancel used to signal scheduler should shut down
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;shutdownCancel&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;CancelFunc&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; the executor, which actually runs the jobs sent to it via the scheduler
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;exec&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;executor&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; the map of jobs registered in the scheduler
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;jobs&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-map z-go&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;uuid&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;UUID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;internalJob&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; the location used by the scheduler for scheduling when relevant
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;location&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Location&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; whether the scheduler has been started or not
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;started&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; globally applied JobOption&amp;#39;s set on all jobs added to the scheduler
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; note: individually set JobOption&amp;#39;s take precedence.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;globalJobOptions&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;JobOption&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; the scheduler&amp;#39;s logger
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;logger&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Logger&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; used to tell the scheduler to start
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;startCh&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-chan z-go&quot;&gt;chan&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; used to report that the scheduler has started
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;startedCh&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-chan z-go&quot;&gt;chan&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; used to tell the scheduler to stop
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;stopCh&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-chan z-go&quot;&gt;chan&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; used to report that the scheduler has stopped
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;stopErrCh&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-chan z-go&quot;&gt;chan&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; used to send all the jobs out when a request is made by the client
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;allJobsOutRequest&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-chan z-go&quot;&gt;chan&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;allJobsOutRequest&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; used to send a jobs out when a request is made by the client
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;jobOutRequestCh&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-chan z-go&quot;&gt;chan&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;jobOutRequest&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; used to run a job on-demand when requested by the client
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;runJobRequestCh&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-chan z-go&quot;&gt;chan&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;runJobRequest&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; new jobs are received here
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;newJobCh&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-chan z-go&quot;&gt;chan&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;newJobIn&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; requests from the client to remove jobs by ID are received here
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;removeJobCh&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-chan z-go&quot;&gt;chan&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;uuid&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;UUID&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; requests from the client to remove jobs by tags are received here
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;removeJobsByTagsCh&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-chan z-go&quot;&gt;chan&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;func &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;getSchedulerStartedField&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;sched gocron&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-c&quot;&gt;Scheduler&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; error&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 1. 使用 reflect.ValueOf() 函数将 gocron.Scheduler 接口转换为反射值。这是反射操作的起点，它创建了一个 reflect.Value 类型的变量，该变量包含了传入接口的运行时表示。
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    schedValue &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; reflect&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;ValueOf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;sched&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 2. 接口的具体实现可能是指针类型。如果是指针，需要使用 Elem() 方法获取指针指向的实际值。这确保我们能够访问到底层结构体，而不是仅仅操作指针本身。
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;if&lt;&#x2F;span&gt; schedValue&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;Kind&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;==&lt;&#x2F;span&gt; reflect&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-c&quot;&gt;Ptr&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;        schedValue &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; schedValue&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;Elem&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 3. 这一步检查反射值是否是结构体类型。因为我们要访问的 started 字段应该是结构体的一个成员，所以需要确认我们操作的确实是一个结构体。如果不是，函数返回错误。
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;if&lt;&#x2F;span&gt; schedValue&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;Kind&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;!=&lt;&#x2F;span&gt; reflect&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-c&quot;&gt;Struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-c&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; fmt&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;scheduler不是结构体，而是&lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; schedValue&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;Kind&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 4. 使用 FieldByName 方法通过字段名称 &amp;quot;started&amp;quot; 获取对应的反射字段。这个方法会在结构体的所有字段中查找匹配的名称。
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    startedField &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; schedValue&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;FieldByName&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;started&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 5. IsValid() 方法检查字段是否存在。如果字段不存在，FieldByName 会返回一个无效的 reflect.Value，这时函数返回错误。
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-c&quot;&gt;!&lt;&#x2F;span&gt;startedField&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;IsValid&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-c&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; fmt&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;无法找到started字段&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 6. 验证找到的字段确实是布尔类型。这确保我们不会错误地处理其他类型的数据，增加了代码的健壮性。
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-c&quot;&gt;if&lt;&#x2F;span&gt; startedField&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;Kind&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-comparison z-c&quot;&gt;!=&lt;&#x2F;span&gt; reflect&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-c&quot;&gt;Bool&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-c&quot;&gt;false&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; fmt&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;Errorf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;started字段不是bool类型，而是&lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; startedField&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;Kind&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 7. 使用unsafe包访问非导出字段，用于绕过 Go 语言的访问控制机制访问非导出字段
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    startedPtr &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; unsafe&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;startedField&lt;span class=&quot;z-punctuation z-accessor z-c&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-variable z-function z-c&quot;&gt;UnsafeAddr&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    started &lt;span class=&quot;z-keyword z-operator z-ternary z-c&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;bool&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;startedPtr&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; started&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; nil
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;步骤4
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FieldByName&lt;&#x2F;code&gt; 方法在无法找到指定名称的字段时，&lt;strong&gt;不会返回 nil 或抛出错误&lt;&#x2F;strong&gt;，而是返回一个特殊的&quot;零值&quot; &lt;code&gt;reflect.Value&lt;&#x2F;code&gt;。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;步骤5
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;IsValid()&lt;&#x2F;code&gt; 方法用于检查一个 &lt;code&gt;reflect.Value&lt;&#x2F;code&gt; 是否包含有效值。在以下情况下 &lt;code&gt;reflect.Value&lt;&#x2F;code&gt; 被视为无效：
&lt;ol&gt;
&lt;li&gt;它是通过零值构造函数 &lt;code&gt;reflect.Value{}&lt;&#x2F;code&gt; 创建的&lt;&#x2F;li&gt;
&lt;li&gt;它代表一个 nil 接口值或 nil 指针&lt;&#x2F;li&gt;
&lt;li&gt;它是 &lt;code&gt;FieldByName&lt;&#x2F;code&gt; 在找不到字段时返回的零值&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;步骤7
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;startedField.UnsafeAddr()&lt;&#x2F;code&gt; 获取字段的内存地址&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;unsafe.Pointer(...)&lt;&#x2F;code&gt; 将该地址转换为通用指针类型&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;(*bool)(startedPtr)&lt;&#x2F;code&gt; 将通用指针转换为 bool 类型指针并解引用，获取实际的 bool 值&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;Claude 3.7 Sonnet Thinking&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Go | Golang项目基础容器镜像选择</title>
          <pubDate>Sat, 12 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-12-go-base-image-select/</link>
          <guid>https://inasa.dev/posts/25-07-12-go-base-image-select/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-12-go-base-image-select/">&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;inasayang.notion.site&#x2F;Golang-CGO-GCC-C-dea39ca517ef4e1b88438aed0f45de8d&quot;&gt;Notion链接&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;在为Golang项目选择基础容器镜像时，需要考虑CGO、GCC和C标准库(glibc&#x2F;musl)的兼容性问题，这些因素会影响应用的构建和运行。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jing-xiang-dui-bi-xiang-xi-fen-xi&quot;&gt;镜像对比详细分析&lt;a class=&quot;zola-anchor&quot; href=&quot;#jing-xiang-dui-bi-xiang-xi-fen-xi&quot; aria-label=&quot;Anchor link for: jing-xiang-dui-bi-xiang-xi-fen-xi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;镜像类型&lt;&#x2F;th&gt;&lt;th&gt;大小&lt;&#x2F;th&gt;&lt;th&gt;C标准库&lt;&#x2F;th&gt;&lt;th&gt;CGO支持&lt;&#x2F;th&gt;&lt;th&gt;GCC可用性&lt;&#x2F;th&gt;&lt;th&gt;优点&lt;&#x2F;th&gt;&lt;th&gt;缺点&lt;&#x2F;th&gt;&lt;th&gt;适用场景&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;golang:latest&lt;&#x2F;td&gt;&lt;td&gt;~950MB&lt;&#x2F;td&gt;&lt;td&gt;glibc&lt;&#x2F;td&gt;&lt;td&gt;完全支持&lt;&#x2F;td&gt;&lt;td&gt;预装&lt;&#x2F;td&gt;&lt;td&gt;完整开发环境，工具齐全，兼容性最好&lt;&#x2F;td&gt;&lt;td&gt;体积大&lt;&#x2F;td&gt;&lt;td&gt;开发&#x2F;测试环境，需要CGO的应用&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;golang:alpine&lt;&#x2F;td&gt;&lt;td&gt;~350MB&lt;&#x2F;td&gt;&lt;td&gt;musl&lt;&#x2F;td&gt;&lt;td&gt;支持但需注意兼容性&lt;&#x2F;td&gt;&lt;td&gt;需要安装&lt;&#x2F;td&gt;&lt;td&gt;体积较小，工具相对齐全&lt;&#x2F;td&gt;&lt;td&gt;musl可能导致兼容性问题&lt;&#x2F;td&gt;&lt;td&gt;开发&#x2F;CI环境，静态编译应用&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;alpine:latest&lt;&#x2F;td&gt;&lt;td&gt;~5MB&lt;&#x2F;td&gt;&lt;td&gt;musl&lt;&#x2F;td&gt;&lt;td&gt;需要安装Go和GCC&lt;&#x2F;td&gt;&lt;td&gt;需要安装&lt;&#x2F;td&gt;&lt;td&gt;体积小，有基础工具&lt;&#x2F;td&gt;&lt;td&gt;musl库兼容性问题&lt;&#x2F;td&gt;&lt;td&gt;简单应用的生产环境&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;debian:stable-slim&lt;&#x2F;td&gt;&lt;td&gt;~80MB&lt;&#x2F;td&gt;&lt;td&gt;glibc&lt;&#x2F;td&gt;&lt;td&gt;支持，需安装Go&lt;&#x2F;td&gt;&lt;td&gt;需安装&lt;&#x2F;td&gt;&lt;td&gt;glibc兼容性好，apt包管理方便&lt;&#x2F;td&gt;&lt;td&gt;比alpine大&lt;&#x2F;td&gt;&lt;td&gt;需要glibc库的应用，CGO依赖&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;scratch&lt;&#x2F;td&gt;&lt;td&gt;~0MB&lt;&#x2F;td&gt;&lt;td&gt;无&lt;&#x2F;td&gt;&lt;td&gt;不支持&lt;&#x2F;td&gt;&lt;td&gt;不支持&lt;&#x2F;td&gt;&lt;td&gt;最小体积&lt;&#x2F;td&gt;&lt;td&gt;无任何工具和库&lt;&#x2F;td&gt;&lt;td&gt;纯静态编译的Go应用&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;distroless&lt;&#x2F;td&gt;&lt;td&gt;~20MB&lt;&#x2F;td&gt;&lt;td&gt;glibc&lt;&#x2F;td&gt;&lt;td&gt;不支持运行时CGO&lt;&#x2F;td&gt;&lt;td&gt;不支持&lt;&#x2F;td&gt;&lt;td&gt;安全性高，体积小&lt;&#x2F;td&gt;&lt;td&gt;缺乏调试工具&lt;&#x2F;td&gt;&lt;td&gt;需要glibc的静态编译应用&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;cgo-gcche-cku-de-kao-liang&quot;&gt;CGO、GCC和C库的考量&lt;a class=&quot;zola-anchor&quot; href=&quot;#cgo-gcche-cku-de-kao-liang&quot; aria-label=&quot;Anchor link for: cgo-gcche-cku-de-kao-liang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;cgo&quot;&gt;CGO&lt;a class=&quot;zola-anchor&quot; href=&quot;#cgo&quot; aria-label=&quot;Anchor link for: cgo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;什么是CGO&lt;&#x2F;strong&gt;：允许Go代码调用C代码的功能&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;考虑因素&lt;&#x2F;strong&gt;：
&lt;ul&gt;
&lt;li&gt;使用CGO=1（默认）会导致动态链接，依赖容器的C库&lt;&#x2F;li&gt;
&lt;li&gt;使用CGO=0可以静态编译，但会失去一些依赖C的功能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;gcc&quot;&gt;GCC&lt;a class=&quot;zola-anchor&quot; href=&quot;#gcc&quot; aria-label=&quot;Anchor link for: gcc&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;用途&lt;&#x2F;strong&gt;：编译C代码、CGO支持所必需&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;考虑因素&lt;&#x2F;strong&gt;：
&lt;ul&gt;
&lt;li&gt;golang:latest预装GCC&lt;&#x2F;li&gt;
&lt;li&gt;alpine和debian:slim需要手动安装&lt;&#x2F;li&gt;
&lt;li&gt;scratch和distroless无法安装&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;cbiao-zhun-ku-glibc-vs-musl&quot;&gt;C标准库：glibc vs musl&lt;a class=&quot;zola-anchor&quot; href=&quot;#cbiao-zhun-ku-glibc-vs-musl&quot; aria-label=&quot;Anchor link for: cbiao-zhun-ku-glibc-vs-musl&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;glibc (GNU C库)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;优点：功能全面，兼容性好，广泛使用&lt;&#x2F;li&gt;
&lt;li&gt;缺点：体积大&lt;&#x2F;li&gt;
&lt;li&gt;使用环境：Debian&#x2F;Ubuntu基础镜像&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;musl libc&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;优点：体积小，注重安全性&lt;&#x2F;li&gt;
&lt;li&gt;缺点：可能有兼容性问题，尤其是与某些动态链接的Go程序&lt;&#x2F;li&gt;
&lt;li&gt;使用环境：Alpine基础镜像&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;zhen-dui-bu-tong-cgochang-jing-de-jian-yi&quot;&gt;针对不同CGO场景的建议&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhen-dui-bu-tong-cgochang-jing-de-jian-yi&quot; aria-label=&quot;Anchor link for: zhen-dui-bu-tong-cgochang-jing-de-jian-yi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1-shi-yong-cgode-ying-yong&quot;&gt;1. 使用CGO的应用&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-shi-yong-cgode-ying-yong&quot; aria-label=&quot;Anchor link for: 1-shi-yong-cgode-ying-yong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;dockerfile&quot; class=&quot;language-dockerfile z-code&quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; 构建阶段
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; golang:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;1.21&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;AS&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;builder&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; . .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;go mod download
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; 默认启用CGO
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;go build -o main .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; 运行阶段
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; debian:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;stable-slim&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; 可能需要安装应用所需的共享库
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;apt-get update &amp;amp;&amp;amp; apt-get install -y --no-install-recommends \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;    libssl1.1 \
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;    &amp;amp;&amp;amp; rm -rf &#x2F;var&#x2F;lib&#x2F;apt&#x2F;lists&#x2F;*
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;builder&lt;&#x2F;span&gt; &#x2F;app&#x2F;main &#x2F;main
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-dockerfile&quot;&gt;CMD &lt;&#x2F;span&gt;[&lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;main&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;2-chun-goying-yong-jin-yong-cgo&quot;&gt;2. 纯Go应用（禁用CGO）&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-chun-goying-yong-jin-yong-cgo&quot; aria-label=&quot;Anchor link for: 2-chun-goying-yong-jin-yong-cgo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;dockerfile&quot; class=&quot;language-dockerfile z-code&quot;&gt;&lt;code class=&quot;language-dockerfile&quot; data-lang=&quot;dockerfile&quot;&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; 构建阶段
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; golang:&lt;span class=&quot;z-entity z-name z-enum z-tag-digest&quot;&gt;1.21-alpine&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;AS&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-stage-name&quot;&gt;builder&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;WORKDIR &lt;&#x2F;span&gt;&#x2F;app
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; . .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;go mod download
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; 禁用CGO，静态编译
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;RUN &lt;&#x2F;span&gt;CGO_ENABLED=0 GOOS=linux go build -o main .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-comment z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-dockerfile&quot;&gt;#&lt;&#x2F;span&gt; 运行阶段可以使用更小的镜像
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;FROM&lt;&#x2F;span&gt; scratch  # 或alpine:latest或distroless
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-control z-dockerfile&quot;&gt;COPY&lt;&#x2F;span&gt; --from=&lt;span class=&quot;z-variable z-stage-name&quot;&gt;builder&lt;&#x2F;span&gt; &#x2F;app&#x2F;main &#x2F;main
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-dockerfile&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-dockerfile&quot;&gt;CMD &lt;&#x2F;span&gt;[&lt;span class=&quot;z-string z-quoted z-double z-dockerfile&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;main&lt;span class=&quot;z-punctuation z-definition z-string z-end z-dockerfile&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;te-shu-chang-jing-jian-yi&quot;&gt;特殊场景建议&lt;a class=&quot;zola-anchor&quot; href=&quot;#te-shu-chang-jing-jian-yi&quot; aria-label=&quot;Anchor link for: te-shu-chang-jing-jian-yi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;需要CGO但担心兼容性&lt;&#x2F;strong&gt;：使用golang:latest或debian:stable-slim基础镜像&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;使用了依赖glibc的Go包&lt;&#x2F;strong&gt;：避免使用alpine或scratch，选择debian:stable-slim或distroless&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;最小化生产镜像同时需要CGO&lt;&#x2F;strong&gt;：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;构建阶段：使用golang:latest或debian构建&lt;&#x2F;li&gt;
&lt;li&gt;运行阶段：使用debian:stable-slim&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;纯静态编译、最小镜像&lt;&#x2F;strong&gt;：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;构建阶段：使用golang:alpine，设置CGO_ENABLED=0&lt;&#x2F;li&gt;
&lt;li&gt;运行阶段：使用scratch或distroless&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;需要调试工具的生产环境&lt;&#x2F;strong&gt;：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;选择alpine或debian:stable-slim，避免scratch和distroless&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;总结：如果您的应用使用CGO或有C库依赖，debian:stable-slim是更安全的选择；如果是纯Go应用可以静态编译，则可以使用更轻量的选项如alpine、scratch或distroless。构建镜像时一定要考虑您的应用是否依赖CGO以及对哪种C标准库有兼容性要求。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;Claude 3.7 Sonnet Thinking&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Go | 表示货币的方法</title>
          <pubDate>Sat, 12 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-12-go-use-currency/</link>
          <guid>https://inasa.dev/posts/25-07-12-go-use-currency/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-12-go-use-currency/">&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;inasayang.notion.site&#x2F;1d8b97323d23800ea4b4c479eb7f8f2f&quot;&gt;Notion链接&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ji-zhun-dan-wei-xuan-ze&quot;&gt;&lt;strong&gt;基准单位选择&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-zhun-dan-wei-xuan-ze&quot; aria-label=&quot;Anchor link for: ji-zhun-dan-wei-xuan-ze&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;货币表示的一个关键问题是选择什么作为基准单位。主流做法有两种：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;使用最小单位&lt;&#x2F;strong&gt;(分、cent等)：将货币以最小单位存储为整数
&lt;ul&gt;
&lt;li&gt;例如：¥10.99存储为1099(分)，$5.25存储为525(美分)&lt;&#x2F;li&gt;
&lt;li&gt;优点：避免浮点数精度问题，计算准确&lt;&#x2F;li&gt;
&lt;li&gt;缺点：需要在展示时进行转换&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;使用定点数&lt;&#x2F;strong&gt;：通常是使用特定库中的decimal类型
&lt;ul&gt;
&lt;li&gt;例如：使用decimal包存储10.99&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;zheng-shu-biao-shi-fa-tui-jian&quot;&gt;&lt;strong&gt;整数表示法（推荐）&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zheng-shu-biao-shi-fa-tui-jian&quot; aria-label=&quot;Anchor link for: zheng-shu-biao-shi-fa-tui-jian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;copy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 以分为单位表示货币
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Money&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;Amount&lt;&#x2F;span&gt;   &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;Currency&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 例如：¥10.99表示为：
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;money&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Money&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Amount&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1099&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Currency&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;CNY&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;2-shi-yong-zhuan-men-de-decimalku&quot;&gt;&lt;strong&gt;2. 使用专门的decimal库&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-shi-yong-zhuan-men-de-decimalku&quot; aria-label=&quot;Anchor link for: 2-shi-yong-zhuan-men-de-decimalku&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;copy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;github.com&#x2F;shopspring&#x2F;decimal&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Money&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;Amount&lt;&#x2F;span&gt;   &lt;span class=&quot;z-variable z-other z-go&quot;&gt;decimal&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Decimal&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;Currency&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 例如：¥10.99表示为：
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;amount&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;decimal&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;NewFromFloat&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-float z-decimal z-go&quot;&gt;10&lt;span class=&quot;z-punctuation z-separator z-decimal z-go&quot;&gt;.&lt;&#x2F;span&gt;99&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;money&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Money&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Amount&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;amount&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Currency&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;CNY&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;3-shi-yong-huo-bi-zhuan-yong-ku&quot;&gt;&lt;strong&gt;3. 使用货币专用库&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-shi-yong-huo-bi-zhuan-yong-ku&quot; aria-label=&quot;Anchor link for: 3-shi-yong-huo-bi-zhuan-yong-ku&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;有一些Go语言的第三方库专门用于处理货币：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;copy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 使用go-money库
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;github.com&#x2F;Rhymond&#x2F;go-money&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 创建10.99人民币
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;money&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;money&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;New&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1099&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;CNY&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;zui-jia-shi-jian&quot;&gt;&lt;strong&gt;最佳实践&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zui-jia-shi-jian&quot; aria-label=&quot;Anchor link for: zui-jia-shi-jian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;避免使用float类型&lt;&#x2F;strong&gt;：浮点数会有精度问题，不适合表示货币&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;推荐使用最小单位的整数&lt;&#x2F;strong&gt;：简单、准确、性能好&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;考虑国际化&lt;&#x2F;strong&gt;：添加货币代码(CNY、USD等)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;处理舍入问题&lt;&#x2F;strong&gt;：明确定义舍入规则&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;进行单元测试&lt;&#x2F;strong&gt;：对所有货币计算进行充分测试&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;最终，选择以最小货币单位（如分）作为基准单位，并使用整数表示，是Golang中处理货币的最佳实践之一。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;Claude 3.7 Sonnet&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | Go Scheduler</title>
          <pubDate>Fri, 11 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-11-go-scheduler/</link>
          <guid>https://inasa.dev/posts/25-07-11-go-scheduler/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-11-go-scheduler/">&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;推荐看原文 https:&#x2F;&#x2F;nghiant3223.github.io&#x2F;2025&#x2F;04&#x2F;15&#x2F;go-scheduler.html ，因为图片是直接用的截图。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;本文主要关注在 ARM 架构上的 Linux 操作系统使用 Go 1.24 编程语言。可能未涵盖其他操作系统或架构的特定平台细节。&lt;&#x2F;p&gt;
&lt;p&gt;内容基于其他资料和我个人对 Go 语言的理解，因此可能不完全准确。欢迎在评论区指出错误或提出建议 😋。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jie-shao&quot;&gt;介绍&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-shao&quot; aria-label=&quot;Anchor link for: jie-shao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;⚠️ 本文假设你已经对 Go 并发（goroutines、channels 等）有基本的了解。如果你是这些概念的新手，建议先复习相关内容再继续阅读。&lt;&#x2F;p&gt;
&lt;p&gt;Go 或 Golang 于 2009 年推出，作为一种构建并发应用的编程语言，受到了稳步增长的欢迎。它设计简洁、高效且易用，特别关注并发编程。&lt;&#x2F;p&gt;
&lt;p&gt;Go 的并发模型构建在 goroutines 的概念上，goroutines 是由 Go 运行时在用户空间管理的轻量级用户线程。Go 提供了有用的同步原语，如 channels，帮助开发者轻松编写并发代码。它还采用了非平凡技术来提高 I&#x2F;O 受限程序的效率。&lt;&#x2F;p&gt;
&lt;p&gt;理解 Go 调度器对 Go 程序员编写高效的并发程序至关重要。它还帮助我们更好地排查性能问题或优化 Go 程序性能。本文将探讨 Go 调度器如何随着时间演进，以及我们编写的 Go 代码在底层是如何运行的。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bian-yi-yu-go-yun-xing-shi&quot;&gt;编译与 Go 运行时&lt;a class=&quot;zola-anchor&quot; href=&quot;#bian-yi-yu-go-yun-xing-shi&quot; aria-label=&quot;Anchor link for: bian-yi-yu-go-yun-xing-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;本文涵盖大量源码解析，因此最好先对 Go 代码的编译和执行有基本了解。Go 程序构建时包含三个阶段：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;编译（Compilation）&lt;&#x2F;strong&gt;：Go 源文件（&lt;code&gt;*.go&lt;&#x2F;code&gt;）被编译成汇编文件（&lt;code&gt;*.s&lt;&#x2F;code&gt;）。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;汇编（Assembling）&lt;&#x2F;strong&gt;：汇编文件（&lt;code&gt;*.s&lt;&#x2F;code&gt;）被组装成目标文件（&lt;code&gt;*.o&lt;&#x2F;code&gt;）。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;链接（Linking）&lt;&#x2F;strong&gt;：目标文件（&lt;code&gt;*.o&lt;&#x2F;code&gt;）被链接在一起，生成单个可执行二进制文件。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;GtIydq9.png%5B&#x2F;img%5D&quot; alt=&quot;How Go code is transformed into an executable binary file&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;要理解 Go 调度器，首先必须了解 Go 运行时。Go 运行时是编程语言的核心，提供了调度、内存管理和数据结构等基本功能。它本质上是一组使 Go 程序能够运行的函数和数据结构的集合。Go 运行时的实现可以在 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;tree&#x2F;go1.24.0&#x2F;src&#x2F;runtime&quot;&gt;runtime&lt;&#x2F;a&gt; 包中找到。Go 运行时由 Go 语言和汇编代码结合编写，汇编代码主要用于处理寄存器等底层操作。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;6Ah4hjm.png&quot; alt=&quot;The role of Go runtime&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;编译时，Go 编译器会将一些关键字和内置函数替换为 Go 运行时的函数调用。例如，用于启动新协程的关键字 &lt;code&gt;go&lt;&#x2F;code&gt; 被替换为对 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L5014-L5030&quot;&gt;&lt;code&gt;runtime.newproc&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 的调用，用于分配新对象的 &lt;code&gt;new&lt;&#x2F;code&gt; 函数被替换为对 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;malloc.go#L1710-L1715&quot;&gt;&lt;code&gt;runtime.newobject&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 的调用。&lt;&#x2F;p&gt;
&lt;p&gt;你可能会惊讶地发现，Go 运行时中的某些函数根本没有 Go 语言实现。例如，&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;stubs.go#L28-L31&quot;&gt;&lt;code&gt;getg&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数被 Go 编译器识别，并在编译期间用低级汇编代码替换。还有些函数，如 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;stubs.go#L214-L214&quot;&gt;&lt;code&gt;gogo&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;，是平台特定的，完全用汇编实现。Go 链接器负责将这些汇编实现与它们对应的 Go 声明连接起来。&lt;&#x2F;p&gt;
&lt;p&gt;在某些情况下，一个函数在其包中看似没有实现，但实际上通过 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;cmd&#x2F;compile#hdr-Linkname_Directive&quot;&gt;&lt;code&gt;&#x2F;&#x2F;go:linkname&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 编译指令链接到了 Go 运行时中的定义。例如，常用的 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;time&#x2F;sleep.go#L12-L14&quot;&gt;&lt;code&gt;time.Sleep&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数就链接到了 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;time.go#L297-L340&quot;&gt;&lt;code&gt;runtime.timeSleep&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 的实际实现。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;yuan-shi-diao-du-qi&quot;&gt;原始调度器&lt;a class=&quot;zola-anchor&quot; href=&quot;#yuan-shi-diao-du-qi&quot; aria-label=&quot;Anchor link for: yuan-shi-diao-du-qi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;⚠️ Go 调度器不是一个独立的对象，而是一组促进调度的函数集合。此外，它并不在专用线程上运行；相反，它运行在与 goroutines 所运行的相同线程上。随着你阅读本文的后续内容，这些概念会变得更加清晰。&lt;&#x2F;p&gt;
&lt;p&gt;如果你曾从事过并发编程，可能对多线程模型有所了解。它描述了用户空间线程（如 Kotlin 和 Lua 中的协程，或 Go 中的 goroutines）如何被复用到单个或多个内核线程上。通常，有三种模型：多对一（N:1）、一对一（1:1）、多对多（M:N）。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;i4Dua6a.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Go 采用多对多（M:N）线程模型，该模型允许多个 goroutine 复用到多个内核线程上。这种方法牺牲了一些复杂性，以利用多核系统的优势，使 Go 程序在系统调用方面更高效，解决了 N:1 和 1:1 模型的问题。由于内核不知道什么是 goroutine，只将线程作为用户空间应用的并发单元，因此由内核线程负责运行调度逻辑、执行 goroutine 代码，并代表 goroutine 进行系统调用。&lt;&#x2F;p&gt;
&lt;p&gt;在早期，特别是 1.1 版本之前，Go 以一种简单的方式实现了 M:N 多线程模型。那时只有两个实体：goroutine（G）和内核线程（M，或称 machines）。使用一个全局运行队列存储所有可运行的 goroutine，并通过锁保护以防止竞态条件。调度器运行在每个内核线程（M）上，负责从全局运行队列中选择 goroutine 并执行它。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;4UDdPOi.png&quot; alt=&quot;Go’s primitive scheduler&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;如今，Go 以其高性能的并发模型闻名，但早期的 Go 并非如此。Go 主要贡献者之一 Dmitry Vyukov 在其著名的&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.google.com&#x2F;document&#x2F;d&#x2F;1TTj4T2JO42uD5ID9e89oa0sLKhJYD0Y_kqxDv3I3XMw&quot;&gt;Scalable Go Scheduler Design&lt;&#x2F;a&gt;中指出了该实现的多个问题：“一般来说，调度器可能会阻碍用户使用对性能至关重要的习惯性细粒度并发。”让我详细解释他的意思。&lt;&#x2F;p&gt;
&lt;p&gt;首先，全局运行队列成为性能瓶颈。当创建一个 goroutine 时，线程必须获取锁才能将其放入全局运行队列。同样，当线程想从全局运行队列中取出一个 goroutine 时，也必须获取锁。锁不是免费的，它会带来锁竞争开销。锁竞争导致性能下降，尤其在高并发场景下更为明显。&lt;&#x2F;p&gt;
&lt;p&gt;其次，线程经常将其关联的 goroutine 切换给另一个线程，这导致了较差的局部性和过多的上下文切换开销。子 goroutine 通常需要与其父 goroutine 通信，因此让子 goroutine 在与其父 goroutine 相同的线程上运行更加高效。&lt;&#x2F;p&gt;
&lt;p&gt;第三，Go 采用了 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;google.github.io&#x2F;tcmalloc&#x2F;design.html&quot;&gt;Thread-caching Malloc&lt;&#x2F;a&gt;，每个线程（M）都有一个线程本地缓存 mcach，用于分配或保存空闲内存。虽然 mcach 仅在执行 Go 代码的线程（M）中使用，但它甚至会附着在阻塞系统调用的线程上，而此时 mcach 根本不被使用。一个 mcach 可能占用多达 2MB 的内存，且直到线程（M）销毁前都不会被释放。由于运行 Go 代码的线程（M）与所有线程（M）数量的比例可能高达 1:100（即太多线程阻塞在系统调用），这可能导致资源过度消耗和数据局部性差。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;diao-du-qi-gai-jin&quot;&gt;调度器改进&lt;a class=&quot;zola-anchor&quot; href=&quot;#diao-du-qi-gai-jin&quot; aria-label=&quot;Anchor link for: diao-du-qi-gai-jin&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;既然你已经了解了早期 Go 调度器存在的问题，我们接下来看看一些改进方案，了解 Go 团队如何解决这些问题，从而拥有了如今高性能的调度器。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fang-an-yi-yin-ru-ben-di-yun-xing-dui-lie&quot;&gt;方案一：引入本地运行队列&lt;a class=&quot;zola-anchor&quot; href=&quot;#fang-an-yi-yin-ru-ben-di-yun-xing-dui-lie&quot; aria-label=&quot;Anchor link for: fang-an-yi-yin-ru-ben-di-yun-xing-dui-lie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;每个线程（M）配备了一个本地运行队列，用于存储可运行的 goroutine。当线程（M）上的一个正在运行的 goroutine（G）通过 go 关键字创建一个新的 goroutine（G1）时，G1 会被加入到线程（M）的本地运行队列中。如果本地队列已满，G1 将被放置到全局运行队列中。在选择要执行的 goroutine 时，线程（M）会先检查自己的本地运行队列，再去访问全局运行队列。因此，这个方案解决了上一节中提到的第一个和第二个问题。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;e9qFZj4.png&quot; alt=&quot;Proposal 1 for scheduler enhancement&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;然而，这个方案无法解决第三个问题。当许多线程（M）阻塞在系统调用中时，它们的 mcach 仍然挂着，导致 Go 调度器自身的内存使用量很高，更不用说我们这些 Go 程序员编写的程序所占用的内存了。&lt;&#x2F;p&gt;
&lt;p&gt;此外，这还引入了另一个性能问题。为了避免被阻塞的线程（如上图中的 M1）中的 goroutine 处于饥饿状态，调度器应该允许其他线程从它那里“窃取”goroutine。然而，当大量线程阻塞时，扫描所有线程以找到非空的运行队列变得代价很高。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fang-an-er-yin-ru-luo-ji-chu-li-qi&quot;&gt;方案二：引入逻辑处理器&lt;a class=&quot;zola-anchor&quot; href=&quot;#fang-an-er-yin-ru-luo-ji-chu-li-qi&quot; aria-label=&quot;Anchor link for: fang-an-er-yin-ru-luo-ji-chu-li-qi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;这个方案在&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.google.com&#x2F;document&#x2F;d&#x2F;1TTj4T2JO42uD5ID9e89oa0sLKhJYD0Y_kqxDv3I3XMw&quot;&gt;Scalable Go Scheduler Design&lt;&#x2F;a&gt;中有所描述，引入了逻辑处理器（P）的概念。逻辑（logical）意味着 P 假装执行 goroutine 代码，但实际上执行的是与 P 关联的线程（M）。线程的本地运行队列和 mcach 现在归 P 所有。&lt;&#x2F;p&gt;
&lt;p&gt;该方案有效地解决了上一节中未解决的问题。由于 mcach 现在挂在 P 上，而不是 M 上，当 G 进行系统调用时，M 会从 P 分离，因此大量 M 进入系统调用时，内存消耗保持较低。同时，由于 P 的数量有限，窃取机制也变得高效。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;kAacNHD.png&quot; alt=&quot;Proposal 2 for scheduler enhancement&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;随着逻辑处理器的引入，多线程模型仍然是 M:N。但在 Go 中，这一模型被特指为 GMP 模型，因为它包含三种实体：goroutine、线程和处理器。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gmp-mo-xing&quot;&gt;GMP 模型&lt;a class=&quot;zola-anchor&quot; href=&quot;#gmp-mo-xing&quot; aria-label=&quot;Anchor link for: gmp-mo-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;goroutine-g&quot;&gt;Goroutine：g&lt;a class=&quot;zola-anchor&quot; href=&quot;#goroutine-g&quot; aria-label=&quot;Anchor link for: goroutine-g&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;当 go 关键字后跟一个函数调用时，会创建一个新的 g 实例，称为 G。G 是表示一个 goroutine 的对象，包含其执行状态、栈以及指向关联函数的程序计数器等元数据。执行一个 goroutine 就是运行 G 所引用的函数。&lt;&#x2F;p&gt;
&lt;p&gt;当一个 goroutine 执行完毕时，它不会被销毁；相反，它变为 dead 状态，并被放入当前处理器 P 的空闲列表中。如果 P 的空闲列表已满，dead 状态的 goroutine 会被移动到全局空闲列表中。当创建新的 goroutine 时，调度器会先尝试复用空闲列表中的 goroutine，而不是重新分配新的。这种回收机制使 goroutine 的创建成本显著低于新线程的创建成本。&lt;&#x2F;p&gt;
&lt;p&gt;下面的图表描述了 GMP 模型中 goroutine 的状态机。为简化起见，部分状态和状态转换被省略。触发状态转换的动作将在后续内容中进行描述。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;i1fCpo5.png&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;OmxeogH.png&quot; alt=&quot;State machine of goroutines in GMP model&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thread-m&quot;&gt;Thread: m&lt;a class=&quot;zola-anchor&quot; href=&quot;#thread-m&quot; aria-label=&quot;Anchor link for: thread-m&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;所有 Go 代码——无论是用户代码、调度器代码还是垃圾收集器代码——都运行在由操作系统内核管理的线程上。为了让 Go 调度器在 GMP 模型中更好地管理线程，引入了表示线程的 m 结构体，m 的一个实例称为 M。&lt;&#x2F;p&gt;
&lt;p&gt;M 维护对当前 goroutine G 的引用；如果 M 正在执行 Go 代码，则维护对当前处理器 P 的引用；如果 M 正在执行系统调用，则维护对前一个处理器 P 的引用；如果 M 即将被创建，则维护对下一个处理器 P 的引用。&lt;&#x2F;p&gt;
&lt;p&gt;每个 M 还持有对一个特殊 goroutine g0 的引用，g0 运行在系统栈上——即由内核为线程提供的栈。与系统栈不同，普通 goroutine 的栈是动态大小的，会根据需要增长和缩小。然而，增长或缩小栈的操作本身必须在一个有效的栈上执行，为此使用了系统栈。当调度器——运行于某个 M 上——需要执行栈管理时，它会从 goroutine 的栈切换到系统栈。除了栈的增长和缩小，像垃圾回收和暂停一个 goroutine（parking a goroutine）等操作也需要在系统栈上执行。每当线程执行此类操作时，都会切换到系统栈，并在 g0 的上下文中执行操作。&lt;&#x2F;p&gt;
&lt;p&gt;与 goroutine 不同，线程在创建后会立即运行调度器代码，因此 M 的初始状态是 running。当 M 被创建或唤醒时，调度器保证总有一个空闲的处理器 P，使得该 P 可以与 M 关联以运行 Go 代码。如果 M 正在执行系统调用，它将与 P 分离（将在“处理系统调用”部分描述），而 P 可能被另一个线程 M1 获取以继续其工作。如果 M 无法从其本地运行队列、全局运行队列或 netpoll（将在“netpoll 工作原理”部分描述）中找到可运行的 goroutine，它会持续循环尝试从其他处理器 P 和全局运行队列中窃取 goroutine。注意，并非所有 M 都会进入 spinning 状态，只有当处于 spinning 状态的线程数量少于繁忙处理器数量的一半时，M 才会进入 spinning 状态。当 M 无事可做时，它不会被销毁，而是进入睡眠状态，等待被另一个处理器 P1 获取（在“寻找可运行的 goroutine”部分描述）。&lt;&#x2F;p&gt;
&lt;p&gt;下面的图表描述了 GMP 模型中线程的状态机。为了简化起见，部分状态和状态转换被省略。spinning 是 idle 的一个子状态，线程在该状态下消耗 CPU 周期专门执行 Go 运行时代码以窃取 goroutine。触发状态转换的动作将在后续内容中描述。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;PGkr90k.png&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;nSU7KNb.png&quot; alt=&quot;State machine of threads in GMP model&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;processor-p&quot;&gt;Processor: p&lt;a class=&quot;zola-anchor&quot; href=&quot;#processor-p&quot; aria-label=&quot;Anchor link for: processor-p&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;p 结构体在概念上代表用于执行 goroutine 的物理处理器。p 的实例被称为 P，它们在程序的引导阶段创建。尽管创建的线程数量可能很大（在 Go 1.24 中达到 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L827-L827&quot;&gt;10000&lt;&#x2F;a&gt;），但处理器的数量通常较少，由 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;runtime#GOMAXPROCS&quot;&gt;GOMAXPROCS&lt;&#x2F;a&gt; 决定。无论状态如何，处理器的数量固定为 GOMAXPROCS。&lt;&#x2F;p&gt;
&lt;p&gt;为了减少全局运行队列上的锁竞争，Go 运行时中的每个处理器 P 都维护一个本地运行队列。本地运行队列不仅仅是一个简单的队列，它由两个部分组成：&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;runtime2.go#L655-L667&quot;&gt;runnext&lt;&#x2F;a&gt;，包含一个单独的优先 goroutine，以及 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;runtime2.go#L654-L654&quot;&gt;runq&lt;&#x2F;a&gt;，这是一个 goroutine 队列。这两个部分都是 P 可执行 goroutine 的来源，但 runnext 存在的主要目的是性能优化。Go 调度器允许 P 从其他处理器 P1 的本地运行队列中窃取 goroutine。只有当前三次试图从 P1 的 runq 窃取 goroutine 失败时，P 才会查询 P1 的 runnext。因此，当 P 想要执行一个 goroutine 时，优先从自己的 runnext 查找可运行 goroutine，可以减少锁竞争。&lt;&#x2F;p&gt;
&lt;p&gt;P 的 runq 组成部分是基于数组的、固定大小的循环队列。由于基于数组且大小固定为 256 个槽，它能提供更好的缓存局部性并减少内存分配开销。固定大小对 P 的本地运行队列是安全的，因为全局运行队列还作为备份。循环队列则允许高效地添加和删除 goroutine，无需移动元素。&lt;&#x2F;p&gt;
&lt;p&gt;每个 P 实例还维护对一些内存管理数据结构的引用，如 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;mcache.go#L13-L55&quot;&gt;mcache&lt;&#x2F;a&gt; 和 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;mpagecache.go#L14-L22&quot;&gt;pageCache&lt;&#x2F;a&gt;。mcache 在线程缓存分配模型中充当前端角色，被 P 用于分配微型和小型对象。另一方面，pageCache 使内存分配器能够在不获取&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.ibm.com&#x2F;docs&#x2F;en&#x2F;sdk-java-technology&#x2F;8?topic=management-heap-allocation#the-allocator&quot;&gt;堆锁&lt;&#x2F;a&gt;的情况下获取内存页，从而在高并发情况下提升性能。&lt;&#x2F;p&gt;
&lt;p&gt;为了使 Go 程序能很好地配合睡眠、超时或间隔等功能，P 还管理由&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Heap_(data_structure)&quot;&gt;最小堆&lt;&#x2F;a&gt;数据结构实现的定时器，其中最近的定时器位于堆顶。当寻找可运行的 goroutine 时，P 也会检查是否有定时器已过期。如果有，P 会将带有定时器的相应 goroutine 添加到其本地运行队列，为该 goroutine 提供运行机会。&lt;&#x2F;p&gt;
&lt;p&gt;下面的图表描述了 GMP 模型中处理器的状态机。为简化起见，部分状态和状态转换被省略。触发状态转换的动作将在后续内容中描述。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;bZHWjx7.png&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;PalMcX9.png&quot; alt=&quot;State machine of processors in GMP model&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;在 Go 程序的早期执行阶段，存在处于 idle 状态的 GOMAXPROCS 个处理器 P。当线程 M 获取一个处理器以运行用户 Go 代码时，P 状态转换为 running。如果当前的 goroutine G 发起了系统调用，P 会与 M 分离并进入 syscall 状态。在系统调用期间，如果 P 被 sysmon 抢占（见非合作式抢占），它会先转换为 idle 状态，然后被交给另一个线程（M1）并进入 running 状态。否则，一旦系统调用完成，P 会重新附加到之前的 M 并恢复 running 状态（见系统调用处理）。&lt;&#x2F;p&gt;
&lt;p&gt;当发生“停止世界”（stop-the-world）垃圾回收时，P 状态转换为 gcStop，且在“停止世界”结束后返回到之前的状态。如果运行时减少了 GOMAXPROCS，冗余的处理器会进入 dead 状态，若后来 GOMAXPROCS 增加，dead 状态的处理器会被重用。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cheng-xu-qi-dong&quot;&gt;程序启动&lt;a class=&quot;zola-anchor&quot; href=&quot;#cheng-xu-qi-dong&quot; aria-label=&quot;Anchor link for: cheng-xu-qi-dong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;为了启用 Go 的调度器，必须在程序启动阶段进行初始化。这个初始化通过汇编中的 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;asm_amd64.s#L159-L159&quot;&gt;&lt;code&gt;runtime·rt0_go&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数来处理。在这个阶段，会创建线程 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L117-L117&quot;&gt;&lt;code&gt;M0&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;（代表主线程）和协程 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L118-L118&quot;&gt;&lt;code&gt;G0&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;（M0 的系统栈协程）。同时，主线程的&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Thread-local_storage&quot;&gt;线程局部存储&lt;&#x2F;a&gt;（TLS）也被设置好，并且 G0 的地址存储在该 TLS 中，以便后续通过 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nghiant3223.github.io&#x2F;2025&#x2F;04&#x2F;15&#x2F;go-scheduler.html#getting-goroutine-getg&quot;&gt;&lt;code&gt;getg&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数获取。&lt;&#x2F;p&gt;
&lt;p&gt;然后，启动过程调用汇编函数 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;asm_amd64.s#L349&quot;&gt;&lt;code&gt;runtime·schedinit&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;，其 Go 语言实现在 runtime.schedinit 中可以找到。该函数执行各种初始化操作，特别是调用 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L5719-L5868&quot;&gt;&lt;code&gt;procresize&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;，它设置最多 GOMAXPROCS 个逻辑处理器 P 处于闲置状态。随后，主线程 M0 关联第一个逻辑处理器，将其状态从闲置（idle）转变为运行中（running），以执行协程。&lt;&#x2F;p&gt;
&lt;p&gt;之后，创建主协程来执行 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L146-L148&quot;&gt;&lt;code&gt;runtime.main&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数，该函数作为 Go 运行时的入口点。在 runtime.main 函数内部，会创建一个专用线程来启动 sysmon，这个内容将在“非合作抢占”章节中介绍。需要注意的是，runtime.main 不同于我们自己编写的 main 函数，后者在运行时表现为 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L134-L135&quot;&gt;&lt;code&gt;main_main&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;主线程随后调用 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L1769-L1769&quot;&gt;&lt;code&gt;mstart&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 来开始在 M0 上执行，启动调度循环（schedule loop）以调度和执行主协程。在 runtime.main 中，经过额外的初始化步骤，控制权最终被交给用户自定义的 main_main 函数，程序开始执行用户的 Go 代码。&lt;&#x2F;p&gt;
&lt;p&gt;值得注意的是，主线程 M0 不仅负责运行主协程，还负责执行其他协程。每当主协程被阻塞——例如等待系统调用或在通道上等待时——主线程会寻找其他可运行的协程并执行它们。&lt;&#x2F;p&gt;
&lt;p&gt;总结起来，程序启动时，有一个协程 G 在执行 main 函数；两个线程——一个是主线程 M0，另一个被创建来启动 sysmon；一个处理器 P0 处于运行状态（running），剩余的 GOMAXPROCS-1 个处理器处于闲置状态（idle）。主线程 M0 最初关联处理器 P0，用于运行主协程 G。&lt;&#x2F;p&gt;
&lt;p&gt;下面的图示说明了程序启动时的状态。假设 GOMAXPROCS 设置为 2，且 main 函数刚刚开始执行。处理器 P0 正在执行主协程，因此处于运行状态。处理器 P1 未执行任何协程，处于闲置状态。主线程 M0 关联处理器 P0 来执行主协程，同时另一个线程 M1 被创建来执行 sysmon。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;h0H8jw7.png&quot; alt=&quot;Program bootstrap in GMP model&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;chuang-jian-xie-cheng&quot;&gt;创建协程&lt;a class=&quot;zola-anchor&quot; href=&quot;#chuang-jian-xie-cheng&quot; aria-label=&quot;Anchor link for: chuang-jian-xie-cheng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Go 提供了一个简单的 API 来启动一个并发执行单元：go func() { ... }()。在底层，Go 运行时做了许多复杂的工作来实现这一点。go 关键字其实是 Go 运行时中 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L5014-L5030&quot;&gt;&lt;code&gt;newproc&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数的语法糖，该函数负责调度一个新的协程。这个函数主要完成三件事：初始化协程，将其放入调用协程所运行的处理器 P 的运行队列中，并唤醒另一个处理器 P1。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;chu-shi-hua-xie-cheng&quot;&gt;初始化协程&lt;a class=&quot;zola-anchor&quot; href=&quot;#chu-shi-hua-xie-cheng&quot; aria-label=&quot;Anchor link for: chu-shi-hua-xie-cheng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;当调用 newproc 时，只有在没有空闲协程可用的情况下，它才会创建一个新的协程 G。协程在执行结束返回后会进入空闲状态。新创建的协程 G 会被初始化一个 2KB 的栈空间，这个大小由 Go 运行时中的常量 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;stack.go#L75-L75&quot;&gt;&lt;code&gt;stackMin&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 定义。此外，&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;stubs.go#L281-L291&quot;&gt;&lt;code&gt;goexit&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;——负责清理逻辑和调度逻辑——会被压入 G 的调用栈，确保在 G 返回时执行。初始化完成后，G 会从 dead 状态转换为 runnable 状态，表示它已准备好被调度执行。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;jiang-xie-cheng-fang-ru-dui-lie&quot;&gt;将协程放入队列&lt;a class=&quot;zola-anchor&quot; href=&quot;#jiang-xie-cheng-fang-ru-dui-lie&quot; aria-label=&quot;Anchor link for: jiang-xie-cheng-fang-ru-dui-lie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;如前所述，每个处理器 P 都有一个运行队列（run queue），由两部分组成：runnext 和 runq。当创建新的协程时，它会被放入 runnext。如果 runnext 已经包含一个协程 G1，调度器会尝试将 G1 移动到 runq（前提是 runq 没有满），然后将新协程 G 放入 runnext。如果 runq 已满，则会将 G1 连同 runq 中一半的协程一起移动到全局运行队列，以减轻处理器 P 的负载。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;wei-shen-me-xin-xie-cheng-bei-fang-ru-runnext&quot;&gt;为什么新协程被放入 runnext&lt;a class=&quot;zola-anchor&quot; href=&quot;#wei-shen-me-xin-xie-cheng-bei-fang-ru-runnext&quot; aria-label=&quot;Anchor link for: wei-shen-me-xin-xie-cheng-bei-fang-ru-runnext&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;局部性原理 (Locality of Reference)，新创建的G通常更&quot;热&quot;
刚创建的goroutine通常会：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;访问相同的内存区域&lt;&#x2F;li&gt;
&lt;li&gt;使用相同的CPU缓存&lt;&#x2F;li&gt;
&lt;li&gt;与创建者有数据依赖&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;优先调度新G的好处&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;CPU缓存命中率更高 → 性能更好&lt;&#x2F;li&gt;
&lt;li&gt;数据局部性更好 → 减少内存访问延迟&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;huan-xing-chu-li-qi&quot;&gt;唤醒处理器&lt;a class=&quot;zola-anchor&quot; href=&quot;#huan-xing-chu-li-qi&quot; aria-label=&quot;Anchor link for: huan-xing-chu-li-qi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;当创建新协程，并且目标是最大化程序的并发性时，当前运行该协程的线程会尝试通过 futex 系统调用唤醒另一个处理器 P。为此，它首先检查是否有空闲的处理器。如果有空闲的处理器 P，则会创建一个新线程或唤醒已有线程进入调度循环（schedule loop），在该循环中线程会寻找可运行的协程进行执行。创建或重用线程的逻辑详见“启动线程”部分。&lt;&#x2F;p&gt;
&lt;p&gt;如前所述，GOMAXPROCS——活动处理器 P 的数量——决定了能并发运行的协程数量。如果所有处理器都忙碌且新协程不断生成，则不会唤醒已有线程或创建新线程。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zheng-ti-liu-cheng-zong-jie&quot;&gt;整体流程总结&lt;a class=&quot;zola-anchor&quot; href=&quot;#zheng-ti-liu-cheng-zong-jie&quot; aria-label=&quot;Anchor link for: zheng-ti-liu-cheng-zong-jie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;下图展示了协程创建的过程。为简化起见，假设 GOMAXPROCS 设置为 2，处理器 P1 尚未进入调度循环（schedule loop），且 main 函数仅不断生成新的协程。由于协程不会执行系统调用（详见“处理系统调用”一节），因此只创建了一个额外的线程 M2 用于关联处理器 P1。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;iFyCkvn.png&quot; alt=&quot;How goroutines are created in GMP model&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;diao-du-xun-huan&quot;&gt;调度循环&lt;a class=&quot;zola-anchor&quot; href=&quot;#diao-du-xun-huan&quot; aria-label=&quot;Anchor link for: diao-du-xun-huan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Go 运行时中的 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L3986-L4068&quot;&gt;&lt;code&gt;schedule&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数负责寻找并执行一个可运行的协程。它会在各种场景下被调用：当创建新线程时、调用 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;runtime#Gosched&quot;&gt;&lt;code&gt;Gosched&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 时、协程被暂停或抢占时，或者协程完成系统调用并返回后。&lt;&#x2F;p&gt;
&lt;p&gt;选择一个可运行协程的过程比较复杂，后续的“寻找可运行协程”一节会详细介绍。一旦选定协程，它会从 &lt;code&gt;runnable&lt;&#x2F;code&gt; 状态转换为 &lt;code&gt;running&lt;&#x2F;code&gt; 状态，表示它已准备好运行。此时，内核线程会调用 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;stubs.go#L214-L214&quot;&gt;&lt;code&gt;gogo&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数开始执行协程。&lt;&#x2F;p&gt;
&lt;p&gt;那么为什么叫做“循环”（loop）呢？正如“初始化协程”一节所述，当一个协程完成时，会调用 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;stubs.go#L281-L291&quot;&gt;&lt;code&gt;goexit&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数。此函数最终导致调用 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L4307-L4310&quot;&gt;&lt;code&gt;goexit0&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;，负责清理终止中的协程，并重新进入 &lt;code&gt;schedule&lt;&#x2F;code&gt; 函数，从而使调度循环得以继续。&lt;&#x2F;p&gt;
&lt;p&gt;下图展示了 Go 运行时中的调度循环流程，其中粉色块代表用户 Go 代码中的阻塞事件，黄色块代表 Go 运行时代码中的阻塞事件。虽然以下内容看起来显而易见，但请注意调度循环是由线程执行的，这也是它在线程初始化之后（蓝色块）发生的原因。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;5DoPP94.png&quot; alt=&quot;The schedule loop in Go runtime&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;但如果主线程卡在调度循环中，进程如何退出呢？只需看看 Go 运行时中的 &lt;code&gt;main&lt;&#x2F;code&gt; 函数，它是由主协程执行的。当 &lt;code&gt;main_main&lt;&#x2F;code&gt;（即 Go 程序员编写的 &lt;code&gt;main&lt;&#x2F;code&gt; 函数的别名）返回后，会调用 &lt;code&gt;exit&lt;&#x2F;code&gt; 系统调用来终止进程。这就是进程能够退出的方式，也是主协程不会等待由 &lt;code&gt;go&lt;&#x2F;code&gt; 关键字生成的协程的原因。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;xun-zhao-ke-yun-xing-de-xie-cheng&quot;&gt;寻找可运行的协程&lt;a class=&quot;zola-anchor&quot; href=&quot;#xun-zhao-ke-yun-xing-de-xie-cheng&quot; aria-label=&quot;Anchor link for: xun-zhao-ke-yun-xing-de-xie-cheng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;线程 M 负责寻找合适的可运行协程，以尽量减少协程饥饿的情况。该逻辑在 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L3267-L3646&quot;&gt;&lt;code&gt;findRunnable&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数中实现，由调度循环调用。&lt;&#x2F;p&gt;
&lt;p&gt;线程 M 按以下顺序查找可运行的协程，发现一个后停止查找：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;检查 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;go.dev&#x2F;blog&#x2F;execution-traces-2024#trace-reader-api&quot;&gt;trace reader&lt;&#x2F;a&gt; 协程的可用性（用于非合作抢占一节）。&lt;&#x2F;li&gt;
&lt;li&gt;检查垃圾回收工作协程的可用性（见垃圾回收器一节）。&lt;&#x2F;li&gt;
&lt;li&gt;1&#x2F;61 的概率检查全局运行队列。&lt;&#x2F;li&gt;
&lt;li&gt;如果 M 正在旋转，检查关联处理器 P 的本地运行队列。&lt;&#x2F;li&gt;
&lt;li&gt;再次检查全局运行队列。&lt;&#x2F;li&gt;
&lt;li&gt;检查 netpoll 中 I&#x2F;O 就绪协程（见 netpoll 工作原理一节）。&lt;&#x2F;li&gt;
&lt;li&gt;从其他处理器 P1 的本地运行队列窃取协程。&lt;&#x2F;li&gt;
&lt;li&gt;再次检查垃圾回收工作协程的可用性。&lt;&#x2F;li&gt;
&lt;li&gt;如果 M 正在旋转，再次检查全局运行队列。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;步骤 1、2 和 8 仅供 Go 运行时内部使用。步骤 1 中，trace reader 用于追踪程序的执行，稍后在“协程抢占”一节会讲到它的具体作用。步骤 2 和 8 允许垃圾回收器与普通协程并发运行。虽然这些步骤不会带来“用户可见”的进展，但它们对 Go 运行时的正常运作至关重要。&lt;&#x2F;p&gt;
&lt;p&gt;步骤 3、5 和 9 不仅仅是抓取一个协程，而是尝试批量抓取以提升效率。批量大小计算公式为 &lt;code&gt;(global_queue_size&#x2F;number_of_processors)+1&lt;&#x2F;code&gt;，但受到几个因素限制：不会超过指定的最大参数，也不会超过 P 的本地队列容量的一半。确定数量后，会弹出一个协程直接返回（立即运行），其余放入 P 的本地运行队列。该批处理方法有助于处理器间的负载均衡，并减少全局队列锁上的争用，因为处理器不必频繁访问全局队列。&lt;&#x2F;p&gt;
&lt;p&gt;步骤 4 略复杂，因为处理器 P 的本地运行队列包含两部分：&lt;code&gt;runnext&lt;&#x2F;code&gt; 和 &lt;code&gt;runq&lt;&#x2F;code&gt;。如果 &lt;code&gt;runnext&lt;&#x2F;code&gt; 非空，它会返回 &lt;code&gt;runnext&lt;&#x2F;code&gt; 中的协程；否则检查 &lt;code&gt;runq&lt;&#x2F;code&gt;，找到可运行的协程并出队。步骤 6 会在 “netpoll 工作原理” 一节详细描述。&lt;&#x2F;p&gt;
&lt;p&gt;步骤 7 是过程最复杂的部分。它会尝试最多四次从另一处理器 P1 窃取任务。前三次尝试只从 P1 的 &lt;code&gt;runq&lt;&#x2F;code&gt; 窃取协程。如果成功，P1 的 &lt;code&gt;runq&lt;&#x2F;code&gt; 中一半的协程会转移到当前处理器 P 的 &lt;code&gt;runq&lt;&#x2F;code&gt;。在最后一次尝试时，会优先从 P1 的 &lt;code&gt;runnext&lt;&#x2F;code&gt; 槽（若有）窃取，若失败则退回到 P1 的 &lt;code&gt;runq&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;注意，&lt;code&gt;findRunnable&lt;&#x2F;code&gt; 不仅查找可运行的协程，还会唤醒在步骤 1 之前进入休眠的协程。协程一旦被唤醒，会被放入执行它的处理器 P 的本地运行队列，等待被线程 M 选中并执行。&lt;&#x2F;p&gt;
&lt;p&gt;如果在步骤 9 之后依然没有找到可运行的协程，线程 M 会在 netpoll 上等待直到最近的 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;time.go#L35-L107&quot;&gt;&lt;code&gt;timer&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 到期——比如当协程从睡眠中唤醒时（因为在 Go 中睡眠会内部创建一个 timer）。为什么 netpoll 会与定时器有关？这是因为 Go 的定时器系统严重依赖于 netpoll，如&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;time.go#L427-L427&quot;&gt;该代码&lt;&#x2F;a&gt;注释所示。netpoll 返回后，M 会重新进入调度循环(schedule loop)，再次搜索可运行的协程。&lt;&#x2F;p&gt;
&lt;p&gt;findRunnable 的前两个行为允许 Go 调度器唤醒休眠中的协程，使程序得以继续执行。这也解释了为什么每个协程（包括 main 协程）在休眠后都有机会运行。我们将在另一篇文章中看看下面这个 Go 程序是如何工作的。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;time&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Sleep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Second&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Sleep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Second&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;如果处理器 P 没有&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;time.go#L35-L107&quot;&gt;定时器&lt;&#x2F;a&gt;，其对应的线程 M 会进入空闲状态。P 会被放入空闲列表，M 通过调用 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nghiant3223.github.io&#x2F;2025&#x2F;04&#x2F;15&#x2F;go-scheduler.html#stop-thread-stopm&quot;&gt;&lt;code&gt;stopm&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数进入睡眠状态，直到另一个线程 M1 唤醒它，通常是在创建新协程时，如“&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;nghiant3223.github.io&#x2F;2025&#x2F;04&#x2F;15&#x2F;go-scheduler.html#waking-up-processor&quot;&gt;唤醒处理器&lt;&#x2F;a&gt;”一节所述。唤醒后，M 会重新进入调度循环，查找并执行可运行的协程。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;xie-cheng-qiang-zhan&quot;&gt;协程抢占&lt;a class=&quot;zola-anchor&quot; href=&quot;#xie-cheng-qiang-zhan&quot; aria-label=&quot;Anchor link for: xie-cheng-qiang-zhan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;抢占是指暂时中断协程执行，以允许其他协程运行，防止协程饥饿。在 Go 中有两种抢占类型：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;非合作抢占：强制运行时间过长的协程停止。&lt;&#x2F;li&gt;
&lt;li&gt;合作抢占：协程主动让出其处理器 P。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;下面我们来看看这两种抢占在 Go 中是如何工作的。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fei-he-zuo-qiang-zhan&quot;&gt;非合作抢占&lt;a class=&quot;zola-anchor&quot; href=&quot;#fei-he-zuo-qiang-zhan&quot; aria-label=&quot;Anchor link for: fei-he-zuo-qiang-zhan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;我们通过一个例子来理解非合作抢占的工作原理。在这个程序中，有两个协程计算斐波那契数列，这是一个包含大量 CPU 运算的紧密循环。为了确保同一时间只有一个协程运行，我们在运行程序时通过设置 &lt;code&gt;GOMAXPROCS&lt;&#x2F;code&gt; 为 1 来限制最大逻辑处理器数量：&lt;code&gt;GOMAXPROCS=1 go run main.go&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;    &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;runtime&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;    &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;time&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;fibonacci&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;   
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;previous&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;current&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;++&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;previous&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;current&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;current&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;previous&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;+&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;current&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;current&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;fibonacci&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1_000_000_000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;fibonacci&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;2_000_000_000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Sleep&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Second&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;由于只有一个处理器 P，可能会出现多种情况。第一种，两个协程都不运行，因为 main 函数已经控制了 P。第二种，一协程运行，另一协程被饿死（无法执行）。第三种，两个协程竟然同时运行——几乎像魔法一样。&lt;&#x2F;p&gt;
&lt;p&gt;幸运的是，Go 提供了工具帮助我们理解调度发生了什么。&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;go.dev&#x2F;pkg&#x2F;runtime&#x2F;trace&quot;&gt;&lt;code&gt;runtime&#x2F;trace&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 包包含一个强大的工具，用于理解和排查 Go 程序。使用它时，我们需要在 main 方法中添加一些代码，将跟踪信息导出到文件。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;file&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Create&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;trace.out&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;trace&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Start&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;file&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;defer&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;trace&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Stop&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;程序运行结束后，我们使用命令 &lt;code&gt;go tool trace trace.out&lt;&#x2F;code&gt; 来可视化跟踪信息。我准备好了 &lt;code&gt;trace.out&lt;&#x2F;code&gt; 文件，如果你想尝试，可以点击这里。在下图中，横轴表示在特定时间点哪个协程在处理器 P 上运行。正如预期的那样，只有一个名为 “Proc 0” 的逻辑处理器 P，这是由于设置了 &lt;code&gt;GOMAXPROCS=1&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;k05qA0A.png&quot; alt=&quot;Trace visualization when program starts&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;通过放大时间线开始部分（按 ‘W’ 键），你可以看到进程从 main.main（main 包中的 main 函数）开始运行，该函数运行在主协程 G1 上。几微秒后，仍在 Proc 0 上，协程 G10 被调度执行 fibonacci 函数，接管了处理器并抢占了 G1。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;EGz58fO.png&quot; alt=&quot;Trace visualization when non-cooperative preemption happens&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;通过缩小视图（按 ‘S’ 键）并略微向右滚动，可以观察到协程 G10 后来被另外一个协程 G9 替代，G9 是下一个运行 fibonacci 函数的实例。这个协程同样运行在 Proc 0 上。请注意图中的 &lt;code&gt;runtime.asyncPreempt:47&lt;&#x2F;code&gt;，我稍后会对此进行解释。&lt;&#x2F;p&gt;
&lt;p&gt;从演示中可以得出结论，Go 能够抢占 CPU 密集型的协程。但为什么这是可能的呢？如果一个协程持续占用 CPU，怎么可能被抢占呢？这是一个难题，在 Go 的问题追踪器上有过长时间的讨论。这个问题直到 Go 1.14 版本才得到解决，当时引入了异步抢占。&lt;&#x2F;p&gt;
&lt;p&gt;在 Go 运行时，有一个守护线程 M（没有绑定处理器 P），称为 sysmon（即系统监控器）。当 sysmon 发现一个协程持续使用处理器 P 超过 10 毫秒（这是 Go 运行时中的常量 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L6245-L6245&quot;&gt;&lt;code&gt;forcePreemptNS&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;），它会通过执行 &lt;code&gt;tgkill&lt;&#x2F;code&gt; 系统调用发送信号，强制抢占正在运行的协程。是的，你没看错。根据 Linux 手册页，&lt;code&gt;tgkill&lt;&#x2F;code&gt; 用于向线程发送信号，而不是杀死线程。这个信号是 &lt;code&gt;SIGURG&lt;&#x2F;code&gt;，选择该信号的原因在这里有说明。&lt;&#x2F;p&gt;
&lt;p&gt;收到 &lt;code&gt;SIGURG&lt;&#x2F;code&gt; 后，程序的执行会转移到信号处理器，这个处理器是在线程初始化时通过调用 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L1879-L1879&quot;&gt;&lt;code&gt;initsig&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数注册的。请注意，信号处理器可以与协程代码或调度器代码并发运行，如下图所示。程序从主程序切换到信号处理器的执行，是由内核触发的。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;6949025&#x2F;how-are-asynchronous-signal-handlers-executed-on-linux&#x2F;&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;unix.stackexchange.com&#x2F;questions&#x2F;733013&#x2F;how-is-a-signal-delivered-in-linux&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;G1IgwkC.png&quot; alt=&quot;Signal delivery and handler execution&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;在信号处理器中，程序计数器被设置到 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;preempt.go#L295-L299&quot;&gt;&lt;code&gt;asyncPreempt&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数，使协程能够被挂起，为抢占腾出空间。在 &lt;code&gt;asyncPreempt&lt;&#x2F;code&gt; 函数的汇编实现中，它会保存协程的寄存器状态，并调用第 47 行的 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;preempt.go#L302-L311&quot;&gt;&lt;code&gt;asyncPreempt2&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数。这就是为什么在可视化中会出现 &lt;code&gt;runtime.asyncPreempt:47&lt;&#x2F;code&gt; 的原因。在 &lt;code&gt;asyncPreempt2&lt;&#x2F;code&gt; 中，线程 M 的协程 g0 会进入 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L4191-L4193&quot;&gt;&lt;code&gt;gopreempt_m&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;，将协程 G 与线程 M 解除关联，并将协程 G 放入全局运行队列。随后线程继续执行调度循环（schedule loop），寻找另一个可运行的协程并执行它。&lt;&#x2F;p&gt;
&lt;p&gt;抢占信号由 sysmon 触发，但实际的抢占直到线程接收到抢占信号后才发生，这种抢占是异步的。这也解释了为什么协程实际上可以运行超过 10 毫秒的时间限制，比如示例中的协程 G9。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;9PZiUen.png&quot; alt=&quot;Non-cooperative preemption in GMP model&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zao-qi-go-zhong-de-xie-zuo-shi-qiang-zhan&quot;&gt;早期 Go 中的协作式抢占&lt;a class=&quot;zola-anchor&quot; href=&quot;#zao-qi-go-zhong-de-xie-zuo-shi-qiang-zhan&quot; aria-label=&quot;Anchor link for: zao-qi-go-zhong-de-xie-zuo-shi-qiang-zhan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;在 Go 的早期阶段，Go 运行时自身无法抢占像上述示例中那样包含紧密循环的协程。作为 Go 程序员，我们必须让协程通过在循环体中调用 &lt;code&gt;runtime.Gosched()&lt;&#x2F;code&gt; 来主动放弃处理器 P，实现协作式调度。Stackoverflow 上曾有&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;13107958&#x2F;what-exactly-does-runtime-gosched-do&quot;&gt;一个问题&lt;&#x2F;a&gt;描述了 &lt;code&gt;runtime.Gosched()&lt;&#x2F;code&gt; 的用法和行为。&lt;&#x2F;p&gt;
&lt;p&gt;从程序员的角度来看，这种方式既繁琐又容易出错，实际上也存在一定的性能问题。因此，Go 团队决定实现一种巧妙的方法，由运行时本身来抢占协程。这个内容将在下一节中讨论。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zi-go-1-14-qi-de-xie-zuo-shi-qiang-zhan&quot;&gt;自 Go 1.14 起的协作式抢占&lt;a class=&quot;zola-anchor&quot; href=&quot;#zi-go-1-14-qi-de-xie-zuo-shi-qiang-zhan&quot; aria-label=&quot;Anchor link for: zi-go-1-14-qi-de-xie-zuo-shi-qiang-zhan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;你是否想过为什么我没有在每次迭代中使用 &lt;code&gt;fmt.Printf&lt;&#x2F;code&gt; 并检查终端，以确定两个协程是否都有运行的机会？这是因为如果那样做的话，抢占就变成了协作式抢占，而不再是非协作式抢占了。&lt;&#x2F;p&gt;
&lt;p&gt;反汇编程序&lt;&#x2F;p&gt;
&lt;p&gt;为了更好地理解这一点，我们先编译程序并分析其汇编代码。由于 Go 编译器会应用各种优化，这会让调试变得更加困难，因此我们需要在构建程序时禁用这些优化。可以通过下面的命令实现：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;go&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;gcflags&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;all=-N -l&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; fibonacci main.go&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;为了更方便调试，我使用 Delve —— 一个功能强大的 Go 调试器，来反汇编 &lt;code&gt;fibonacci&lt;&#x2F;code&gt; 函数：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dlv&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; exec .&#x2F;fibonacci&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;进入调试器后，我运行以下命令查看 &lt;code&gt;fibonacci&lt;&#x2F;code&gt; 函数的汇编代码：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;disassemble&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;l&lt;&#x2F;span&gt; main.fibonacci&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;你可以在这里找到原始程序的汇编代码。由于我是在本地机器（darwin&#x2F;arm64）上构建程序，你机器上生成的汇编代码可能会有所不同。&lt;&#x2F;p&gt;
&lt;p&gt;以上都准备好了，让我们看看 &lt;code&gt;fibonacci&lt;&#x2F;code&gt; 函数的汇编代码，以了解它的具体执行内容。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;11&lt;&#x2F;span&gt;      &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;1023e8890&lt;&#x2F;span&gt;     &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;900&lt;&#x2F;span&gt;b&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;40&lt;&#x2F;span&gt;f&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;9&lt;&#x2F;span&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;MOVD&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;16&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;R28&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;R16&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;11&lt;&#x2F;span&gt;      &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;1023e8894&lt;&#x2F;span&gt;     &lt;span class=&quot;z-variable z-other z-go&quot;&gt;f1c300d1&lt;&#x2F;span&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;SUB&lt;&#x2F;span&gt; $&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;48&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;RSP&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;R17&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;11&lt;&#x2F;span&gt;      &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;1023e8898&lt;&#x2F;span&gt;     &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;3&lt;&#x2F;span&gt;f&lt;span class=&quot;z-constant z-numeric z-integer z-octal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0&lt;&#x2F;span&gt;210&lt;&#x2F;span&gt;eb        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;CMP&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;R16&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;R17&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;11&lt;&#x2F;span&gt;      &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;1023e889c&lt;&#x2F;span&gt;     &lt;span class=&quot;z-invalid z-illegal z-go&quot;&gt;09&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;c&lt;span class=&quot;z-constant z-numeric z-integer z-octal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0&lt;&#x2F;span&gt;054&lt;&#x2F;span&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;BLS&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;96&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;PC&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;17&lt;&#x2F;span&gt;      &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;1023e8910&lt;&#x2F;span&gt;     &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;6078&lt;&#x2F;span&gt;fd&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;97&lt;&#x2F;span&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;CALL&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;runtime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;convT64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;SB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;17&lt;&#x2F;span&gt;      &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;1023e895c&lt;&#x2F;span&gt;     &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;4&lt;&#x2F;span&gt;d&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;78&lt;&#x2F;span&gt;fd&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;97&lt;&#x2F;span&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;CALL&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;runtime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;convT64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;SB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;20&lt;&#x2F;span&gt;      &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;1023e8a18&lt;&#x2F;span&gt;     &lt;span class=&quot;z-variable z-other z-go&quot;&gt;c0035fd6&lt;&#x2F;span&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;RET&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;11&lt;&#x2F;span&gt;      &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;1023e8a1c&lt;&#x2F;span&gt;     &lt;span class=&quot;z-variable z-other z-go&quot;&gt;e00700f9&lt;&#x2F;span&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;MOVD&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;R0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;RSP&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;11&lt;&#x2F;span&gt;      &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;1023e8a20&lt;&#x2F;span&gt;     &lt;span class=&quot;z-variable z-other z-go&quot;&gt;e3031eaa&lt;&#x2F;span&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;MOVD&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;R30&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;R3&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;11&lt;&#x2F;span&gt;      &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;1023e8a24&lt;&#x2F;span&gt;     &lt;span class=&quot;z-variable z-other z-go&quot;&gt;dbe7fe97&lt;&#x2F;span&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;CALL&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;runtime&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;morestack_noctxt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;SB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;11&lt;&#x2F;span&gt;      &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;1023e8a28&lt;&#x2F;span&gt;     &lt;span class=&quot;z-variable z-other z-go&quot;&gt;e00740f9&lt;&#x2F;span&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;MOVD&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;RSP&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;R0&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;11&lt;&#x2F;span&gt;      &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;1023e8a2c&lt;&#x2F;span&gt;     &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;99&lt;&#x2F;span&gt;ffff&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;17&lt;&#x2F;span&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;JMP&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;fibonacci&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;SB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;MOVD 16(R28), R16&lt;&#x2F;code&gt; 指令从寄存器 &lt;code&gt;R28&lt;&#x2F;code&gt; 的偏移量 16 处加载一个值，&lt;code&gt;R28&lt;&#x2F;code&gt; 保存了协程数据结构 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;runtime2.go#L396-L396&quot;&gt;&lt;code&gt;g&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;，并将该值存储到寄存器 &lt;code&gt;R16&lt;&#x2F;code&gt; 中。加载的值是 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;runtime2.go#L405-L405&quot;&gt;&lt;code&gt;stackguard0&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 字段，它作为当前协程的栈保护。那什么是栈保护呢？你可能知道协程的栈是可动态增长的，但 Go 运行时如何确定何时需要增长呢？栈保护是放置在栈末尾的一个特殊值。当栈指针达到这个值时，Go 运行时检测到栈快满了，需要增长——这正是接下来的三条指令所做的。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;SUB $48, RSP, R17&lt;&#x2F;code&gt; 指令从寄存器 &lt;code&gt;RPS&lt;&#x2F;code&gt; 取出协程栈指针，加载到寄存器 &lt;code&gt;R17&lt;&#x2F;code&gt;，并从中减去 48。&lt;br &#x2F;&gt;
&lt;code&gt;CMP R16, R17&lt;&#x2F;code&gt; 将栈保护和栈指针进行比较，&lt;br &#x2F;&gt;
&lt;code&gt;BLS 96(PC)&lt;&#x2F;code&gt; 会在栈指针小于等于（注意，这里是“less or equal”，而不是“大于等于”）栈保护时跳转到程序中 96 条指令以后的地址。为什么用“≤”而不用“≥”呢？因为栈向下增长，所以栈指针总是比栈保护要大。&lt;&#x2F;p&gt;
&lt;p&gt;你是否想过为什么这些指令在 Go 代码中看不到，但在汇编代码中却出现了？这是因为编译时，Go 编译器会自动将这些指令插入到函数的序言（&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Function_prologue_and_epilogue&quot;&gt;prologue&lt;&#x2F;a&gt;）中。这个机制适用于所有函数，比如 &lt;code&gt;fmt.Println&lt;&#x2F;code&gt;，而不仅仅是我们的 &lt;code&gt;fibonacci&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;执行到 96 条指令后，会遇到 &lt;code&gt;MOVD R0, 8(RSP)&lt;&#x2F;code&gt; 指令，接着执行&lt;br &#x2F;&gt;
&lt;code&gt;CALL runtime.morestack_noctxt(SB)&lt;&#x2F;code&gt;。&lt;br &#x2F;&gt;
&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;asm_arm64.s#L348-L348&quot;&gt;&lt;code&gt;runtime.morestack_noctxt&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数最终会调用 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;stack.go#L966-L966&quot;&gt;&lt;code&gt;newstack&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 来扩展栈，并可选地进入 &lt;code&gt;gopreempt_m&lt;&#x2F;code&gt;，触发前面提到的非协作式抢占。协作式抢占的关键点在于进入 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L4191-L4193&quot;&gt;&lt;code&gt;gopreempt_m&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 的条件，即 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;stack.go#L1025-L1025&quot;&gt;&lt;code&gt;stackguard0 == stackPreempt&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;，这意味着只要协程想要扩展它的栈，且其 &lt;code&gt;stackguard0&lt;&#x2F;code&gt; 之前被设置成了 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;stack.go#L128-L130&quot;&gt;&lt;code&gt;stackPreempt&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;，它就会被抢占。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;stackPreempt&lt;&#x2F;code&gt; 可以由 &lt;code&gt;sysmon&lt;&#x2F;code&gt; 设置，条件是某个协程已运行超过 10 毫秒。之后，如果该协程调用函数，或者被线程的信号处理器以非协作方式抢占，协程就会被协作式抢占，以先发生者为准。它也可以在协程进入或退出系统调用时，或者在垃圾回收的追踪阶段被设置。有关详细内容，请参见 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L6366-L6366&quot;&gt;sysmon preemption&lt;&#x2F;a&gt;、&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L4525-L4525&quot;&gt;syscall entry&lt;&#x2F;a&gt;&#x2F;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;proc.go#L4663-L4663&quot;&gt;exit&lt;&#x2F;a&gt;、&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;runtime&#x2F;trace.go#L389-L389&quot;&gt;garbage collector tracing&lt;&#x2F;a&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;追踪可视化&lt;&#x2F;p&gt;
&lt;p&gt;好了，让我们重新运行程序——确保已经设置了 &lt;code&gt;GOMAXPROCS=1&lt;&#x2F;code&gt;，然后检查追踪结果。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;j5Fz7mj.png&quot; alt=&quot;Trace visualization when cooperative preemption happens&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;你可以清楚地看到，协程在仅仅几十微秒后就会放弃逻辑处理器——这与非协作抢占不同，后者可能会持续超过 10 毫秒。值得注意的是，协程 G9 的堆栈跟踪在循环体内的 &lt;code&gt;fmt.Printf&lt;&#x2F;code&gt; 处结束，说明了函数序言中的栈保护检查。这个可视化图准确地展示了协作抢占的过程，即协程&lt;strong&gt;主动&lt;&#x2F;strong&gt;让出处理器。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;VJqZpfl.png&quot; alt=&quot;Cooperative preemption in GMP model&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;xi-tong-diao-yong-chu-li&quot;&gt;系统调用处理&lt;a class=&quot;zola-anchor&quot; href=&quot;#xi-tong-diao-yong-chu-li&quot; aria-label=&quot;Anchor link for: xi-tong-diao-yong-chu-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;系统调用是内核提供的服务，用户空间应用通过 API 访问这些服务。这些服务包括基本操作，例如读取文件、建立连接或分配内存。在 Go 语言中，你很少需要直接与系统调用交互，因为标准库提供了更高级的抽象来简化这些任务。&lt;&#x2F;p&gt;
&lt;p&gt;然而，理解系统调用的工作原理对于深入了解 Go 运行时、标准库内部实现以及性能优化至关重要。Go 运行时采用了 M:N 线程模型，并通过逻辑处理器 P 进一步优化，使得其处理系统调用的方法尤为有趣。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;xi-tong-diao-yong-fen-lei&quot;&gt;系统调用分类&lt;a class=&quot;zola-anchor&quot; href=&quot;#xi-tong-diao-yong-fen-lei&quot; aria-label=&quot;Anchor link for: xi-tong-diao-yong-fen-lei&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;在 Go 运行时，针对内核系统调用有两个封装函数：&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;syscall&#x2F;syscall_linux.go#L54-L56&quot;&gt;&lt;code&gt;RawSyscall&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 和 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;syscall&#x2F;syscall_linux.go#L72-L89&quot;&gt;&lt;code&gt;Syscall&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;。我们编写的 Go 代码会使用这些函数来调用系统调用。每个函数都接受一个系统调用编号及其参数，并返回结果值和错误码。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;Syscall&lt;&#x2F;code&gt; 通常用于那些执行时间不可预测的操作，例如从文件读取或写入 HTTP 响应。由于这些操作的持续时间是非确定性的，Go 运行时需要对其进行管理，以确保资源的高效使用。该函数协调协程 &lt;code&gt;G&lt;&#x2F;code&gt;、线程 &lt;code&gt;M&lt;&#x2F;code&gt; 和处理器 &lt;code&gt;P&lt;&#x2F;code&gt;，使得 Go 运行时能够在阻塞系统调用过程中保持性能和响应性。&lt;&#x2F;p&gt;
&lt;p&gt;不过，并非所有系统调用都是不可预测的。例如，获取进程 ID 或当前时间通常快速且稳定。对于此类操作，使用 &lt;code&gt;RawSyscall&lt;&#x2F;code&gt;。由于这类调用不会涉及调度，协程 &lt;code&gt;G&lt;&#x2F;code&gt;、线程 &lt;code&gt;M&lt;&#x2F;code&gt; 和处理器 &lt;code&gt;P&lt;&#x2F;code&gt; 之间的关联在原始系统调用执行时保持不变。&lt;&#x2F;p&gt;
&lt;p&gt;在内部，&lt;code&gt;Syscall&lt;&#x2F;code&gt; 会调用 &lt;code&gt;RawSyscall&lt;&#x2F;code&gt; 来执行实际的系统调用，但会在其外层包装附加的调度逻辑，这部分内容将在下一节详细介绍。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Syscall&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;trap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;a1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;a2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;a3&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;r1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;r2&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Errno&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-function z-go&quot;&gt;runtime_entersyscall&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;r1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;r2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;RawSyscall6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;trap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;a1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;a2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;a3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-function z-go&quot;&gt;runtime_exitsyscall&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;syscall-zhong-de-diao-du&quot;&gt;&lt;code&gt;Syscall&lt;&#x2F;code&gt; 中的调度&lt;a class=&quot;zola-anchor&quot; href=&quot;#syscall-zhong-de-diao-du&quot; aria-label=&quot;Anchor link for: syscall-zhong-de-diao-du&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;调度逻辑分别由 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;syscall&#x2F;syscall_linux.go#L28-L29&quot;&gt;&lt;code&gt;runtime_entersyscall&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数和 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;syscall&#x2F;syscall_linux.go#L31-L32&quot;&gt;&lt;code&gt;runtime_exitsyscall&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; 函数实现，分别在实际系统调用之前和之后执行。底层这两个函数实际上对应的是 &lt;code&gt;runtime.entersyscall&lt;&#x2F;code&gt; 和 &lt;code&gt;runtime.exitsyscall&lt;&#x2F;code&gt;，它们的关联关系在编译时就已建立。&lt;&#x2F;p&gt;
&lt;p&gt;在进行实际系统调用之前，Go 运行时会记录发起系统调用的协程不再使用 CPU。协程 &lt;code&gt;G&lt;&#x2F;code&gt; 从 &lt;code&gt;running&lt;&#x2F;code&gt; 状态转变为 &lt;code&gt;syscall&lt;&#x2F;code&gt; 状态，且其栈指针、程序计数器和帧指针都会被保存以备后续恢复。线程 &lt;code&gt;M&lt;&#x2F;code&gt; 和处理器 &lt;code&gt;P&lt;&#x2F;code&gt; 的关联关系暂时解除，&lt;code&gt;P&lt;&#x2F;code&gt; 也转变为 &lt;code&gt;syscall&lt;&#x2F;code&gt; 状态。该逻辑由 &lt;code&gt;runtime.reentersyscall&lt;&#x2F;code&gt; 实现，该函数在 &lt;code&gt;runtime.entersyscall&lt;&#x2F;code&gt; 中被调用。&lt;&#x2F;p&gt;
&lt;p&gt;有趣的是，&lt;code&gt;sysmon&lt;&#x2F;code&gt;（前文“非协作抢占”部分提及）不仅会监控运行协程代码的处理器（即处于 &lt;code&gt;running&lt;&#x2F;code&gt; 状态的 &lt;code&gt;P&lt;&#x2F;code&gt;），还会监控执行系统调用的处理器（即处于 &lt;code&gt;syscall&lt;&#x2F;code&gt; 状态的 &lt;code&gt;P&lt;&#x2F;code&gt;）。如果一个 &lt;code&gt;P&lt;&#x2F;code&gt; 在 &lt;code&gt;syscall&lt;&#x2F;code&gt; 状态下超过 10 毫秒，&lt;code&gt;sysmon&lt;&#x2F;code&gt; 不会非协作抢占运行中的协程，而是发生“处理器交接”（processor handoff）。这意味着协程 &lt;code&gt;G&lt;&#x2F;code&gt; 与线程 &lt;code&gt;M&lt;&#x2F;code&gt; 的关联保持不变，并且会将另一线程 &lt;code&gt;M1&lt;&#x2F;code&gt; 关联到该 &lt;code&gt;P&lt;&#x2F;code&gt;，从而允许可运行的协程在 &lt;code&gt;M1&lt;&#x2F;code&gt; 线程上执行。显然，由于 &lt;code&gt;P&lt;&#x2F;code&gt; 正在执行代码，其状态改变为 &lt;code&gt;running&lt;&#x2F;code&gt;，不再是之前的 &lt;code&gt;syscall&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;需要注意的是，在系统调用仍在进行过程中，无论 &lt;code&gt;sysmon&lt;&#x2F;code&gt; 是否抢占了 &lt;code&gt;P&lt;&#x2F;code&gt;，协程 &lt;code&gt;G&lt;&#x2F;code&gt; 与线程 &lt;code&gt;M&lt;&#x2F;code&gt; 的关联始终保持存在。为什么？因为 Go 程序（包括 Go 运行时和我们编写的 Go 代码）只是用户空间进程，唯一的执行单位是线程，而线程负责运行 Go 运行时代码、执行 Go 代码并发起系统调用。如果线程 &lt;code&gt;M&lt;&#x2F;code&gt; 代表某个协程 &lt;code&gt;G&lt;&#x2F;code&gt; 发起系统调用，即使线程 &lt;code&gt;M&lt;&#x2F;code&gt; 被 &lt;code&gt;sysmon&lt;&#x2F;code&gt; 抢占了，也会继续阻塞等待系统调用完成，然后才调用 &lt;code&gt;runtime.exitsyscall&lt;&#x2F;code&gt; 函数。&lt;&#x2F;p&gt;
&lt;p&gt;另一个重要点是：每当处理器 &lt;code&gt;P&lt;&#x2F;code&gt; 处于 &lt;code&gt;syscall&lt;&#x2F;code&gt; 状态时，**它不能被另一个线程 &lt;code&gt;M&lt;&#x2F;code&gt; 占用以执行代码，直到 &lt;code&gt;sysmon&lt;&#x2F;code&gt; 抢占它或系统调用完成为止。**因此，如果多个系统调用同时发生，程序（不包括系统调用部分）将不会有任何进展。这也是为什么 Dgraph 数据库将 &lt;code&gt;GOMAXPROCS&lt;&#x2F;code&gt; 硬编码设置为128，以“&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hypermodeinc&#x2F;dgraph&#x2F;blob&#x2F;v24.1.2&#x2F;dgraph&#x2F;main.go#L33-L36&quot;&gt;允许更多的磁盘 I&#x2F;O 调用被调度&lt;&#x2F;a&gt;”。&lt;&#x2F;p&gt;
&lt;p&gt;如 &lt;code&gt;runtime.exitsyscall&lt;&#x2F;code&gt; 中所述，系统调用完成后调度器有两条路径可走：快速路径和慢速路径。后者只有在前者不可行时才会执行。&lt;&#x2F;p&gt;
&lt;p&gt;快速路径发生在有可用处理器 &lt;code&gt;P&lt;&#x2F;code&gt; 用于执行刚完成系统调用的协程 &lt;code&gt;G&lt;&#x2F;code&gt; 时。这个 &lt;code&gt;P&lt;&#x2F;code&gt; 可以是之前执行过协程 &lt;code&gt;G&lt;&#x2F;code&gt; 的同一个（如果它仍处于 &lt;code&gt;syscall&lt;&#x2F;code&gt; 状态，即没有被 &lt;code&gt;sysmon&lt;&#x2F;code&gt; 抢占），也可以是任何当前处于空闲状态的处理器 &lt;code&gt;P1&lt;&#x2F;code&gt;，以先找到者为准。需要注意的是，系统调用完成时，之前的处理器 &lt;code&gt;P&lt;&#x2F;code&gt; 可能已不再处于 &lt;code&gt;syscall&lt;&#x2F;code&gt; 状态，因为它已被 &lt;code&gt;sysmon&lt;&#x2F;code&gt; 抢占。在快速路径退出之前，协程 &lt;code&gt;G&lt;&#x2F;code&gt; 会从 &lt;code&gt;syscall&lt;&#x2F;code&gt; 状态切换为 &lt;code&gt;running&lt;&#x2F;code&gt; 状态。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;yL1r2mr.png&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;在慢速路径中，调度器会再次尝试获取任何空闲的处理器 &lt;code&gt;P&lt;&#x2F;code&gt;。如果找到了，协程 &lt;code&gt;G&lt;&#x2F;code&gt; 会被调度在该处理器 &lt;code&gt;P&lt;&#x2F;code&gt; 上运行。否则，协程 &lt;code&gt;G&lt;&#x2F;code&gt; 会被加入全局运行队列，同时关联的线程 &lt;code&gt;M&lt;&#x2F;code&gt; 会被 &lt;code&gt;stopm&lt;&#x2F;code&gt; 函数停止，等待被唤醒以继续执行调度循环。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wang-luo-i-o-he-wen-jian-i-o&quot;&gt;网络 I&#x2F;O 和文件 I&#x2F;O&lt;a class=&quot;zola-anchor&quot; href=&quot;#wang-luo-i-o-he-wen-jian-i-o&quot; aria-label=&quot;Anchor link for: wang-luo-i-o-he-wen-jian-i-o&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;这项调查显示，75% 的 Go 使用场景是网络服务，45% 是静态网站。这并非巧合，Go 设计之初就注重高效的 I&#x2F;O 操作，以解决臭名昭著的问题——C10K。为了了解 Go 是如何解决该问题的，我们来看看 Go 在底层如何处理 I&#x2F;O 操作。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;http-fu-wu-qi-di-ceng-yuan-li&quot;&gt;HTTP 服务器底层原理&lt;a class=&quot;zola-anchor&quot; href=&quot;#http-fu-wu-qi-di-ceng-yuan-li&quot; aria-label=&quot;Anchor link for: http-fu-wu-qi-di-ceng-yuan-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;在 Go 中，启动一个 HTTP 服务器非常简单明了。例如：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;net&#x2F;http&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;HandleFunc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;w&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ResponseWriter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;r&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;w&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;WriteHeader&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;200&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;ListenAndServe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;:80&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;像 &lt;code&gt;http.ListenAndServe()&lt;&#x2F;code&gt; 和 &lt;code&gt;http.HandleFunc()&lt;&#x2F;code&gt; 这样的函数看起来可能非常简单，但在底层，它们抽象了许多底层网络的复杂性。Go 依赖许多基础的 socket 操作（如下图所示）来管理网络通信。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;AQrvoNQ.png&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;具体来说，&lt;code&gt;http.ListenAndServe()&lt;&#x2F;code&gt; 利用 &lt;code&gt;socket()&lt;&#x2F;code&gt;、&lt;code&gt;bind()&lt;&#x2F;code&gt;、&lt;code&gt;listen()&lt;&#x2F;code&gt;、&lt;code&gt;accept()&lt;&#x2F;code&gt; 这些系统调用来创建 TCP 套接字，这些套接字本质上是文件描述符。它将 TCP 监听套接字绑定到指定的地址和端口，监听传入连接，并创建一个新的已连接套接字来处理客户端请求。整个过程无需你编写套接字处理代码。同样地，&lt;code&gt;http.HandleFunc()&lt;&#x2F;code&gt; 用于注册你的处理函数，抽象了底层细节，比如使用 &lt;code&gt;read()&lt;&#x2F;code&gt; 系统调用读取数据，使用 &lt;code&gt;write()&lt;&#x2F;code&gt; 系统调用向网络套接字写入数据。&lt;&#x2F;p&gt;
&lt;p&gt;然而，对于 HTTP 服务器来说，高效地处理成千上万的并发请求并没有那么简单。Go 采用了多种技术来实现这一点。让我们仔细看看 Linux 中一些重要的 I&#x2F;O 模型，以及 Go 如何利用它们。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zu-sai-i-o-fei-zu-sai-i-o-ji-i-o-duo-lu-fu-yong&quot;&gt;阻塞 I&#x2F;O、非阻塞 I&#x2F;O 及 I&#x2F;O 多路复用&lt;a class=&quot;zola-anchor&quot; href=&quot;#zu-sai-i-o-fei-zu-sai-i-o-ji-i-o-duo-lu-fu-yong&quot; aria-label=&quot;Anchor link for: zu-sai-i-o-fei-zu-sai-i-o-ji-i-o-duo-lu-fu-yong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;I&#x2F;O 操作可以是阻塞的，也可以是非阻塞的。当线程发出阻塞系统调用时，其执行将被挂起，直到系统调用完成并返回所请求的数据。相反，非阻塞 I&#x2F;O 不会挂起线程；如果数据可用，则直接返回所请求的数据；如果数据尚不可用，则返回错误（例如 &lt;code&gt;EAGAIN&lt;&#x2F;code&gt; 或 &lt;code&gt;EWOULDBLOCK&lt;&#x2F;code&gt;）。阻塞 I&#x2F;O 实现较为简单，但效率较低，因为它需要为 N 个连接生成 N 个线程。相比之下，非阻塞 I&#x2F;O 复杂一些，但如果实现得当，能够显著提升资源利用率。下面的图示将直观对比这两种模型。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;gB08b1x.png&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;另一种值得一提的 I&#x2F;O 模型是 I&#x2F;O 多路复用，其中使用 &lt;code&gt;select&lt;&#x2F;code&gt; 或 &lt;code&gt;poll&lt;&#x2F;code&gt; 系统调用等待一组文件描述符中的某一个变为可进行 I&#x2F;O 操作。在该模型中，应用程序会阻塞在这些系统调用之一上，而不是阻塞在具体的 I&#x2F;O 系统调用（如上图所示的 &lt;code&gt;recvfrom&lt;&#x2F;code&gt;）上。当 &lt;code&gt;select&lt;&#x2F;code&gt; 返回表明套接字可读时，应用程序调用 &lt;code&gt;recvfrom&lt;&#x2F;code&gt; 将请求的数据复制到用户空间的应用缓冲区。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;kFx8inI.png&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;go-de-i-o-mo-xing&quot;&gt;Go 的 I&#x2F;O 模型&lt;a class=&quot;zola-anchor&quot; href=&quot;#go-de-i-o-mo-xing&quot; aria-label=&quot;Anchor link for: go-de-i-o-mo-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Go 结合了非阻塞 I&#x2F;O 和 I&#x2F;O 多路复用来高效地处理 I&#x2F;O 操作。由于 &lt;code&gt;select&lt;&#x2F;code&gt; 和 &lt;code&gt;poll&lt;&#x2F;code&gt; 存在性能瓶颈——如本文博客所述——Go 避免使用它们，转而采用更具可扩展性的替代方案：Linux 上的 &lt;code&gt;epoll&lt;&#x2F;code&gt;，Darwin 上的 &lt;code&gt;kqueue&lt;&#x2F;code&gt;，以及 Windows 上的 IOCP。Go 引入了 netpoll，一个抽象这些替代方案的函数，用以提供跨不同操作系统的统一 I&#x2F;O 多路复用接口。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;netpoll-de-gong-zuo-yuan-li&quot;&gt;netpoll 的工作原理&lt;a class=&quot;zola-anchor&quot; href=&quot;#netpoll-de-gong-zuo-yuan-li&quot; aria-label=&quot;Anchor link for: netpoll-de-gong-zuo-yuan-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;使用 netpoll 需要四个步骤：在内核空间创建一个 &lt;code&gt;epoll&lt;&#x2F;code&gt; 实例，使用该 &lt;code&gt;epoll&lt;&#x2F;code&gt; 实例注册文件描述符，&lt;code&gt;epoll&lt;&#x2F;code&gt; 轮询这些文件描述符的 I&#x2F;O 状态，最后从 &lt;code&gt;epoll&lt;&#x2F;code&gt; 实例中注销文件描述符。下面我们来看 Go 是如何实现这些步骤的。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;chuang-jian-epoll-shi-li-ji-zhu-ce-goroutine&quot;&gt;创建 epoll 实例及注册 Goroutine&lt;a class=&quot;zola-anchor&quot; href=&quot;#chuang-jian-epoll-shi-li-ji-zhu-ce-goroutine&quot; aria-label=&quot;Anchor link for: chuang-jian-epoll-shi-li-ji-zhu-ce-goroutine&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;当 TCP 监听器&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;go1.24.0&#x2F;src&#x2F;net&#x2F;tcpsock.go#L374-L385&quot;&gt;接受&lt;&#x2F;a&gt;一个连接时，会调用带有 &lt;code&gt;SOCK_NONBLOCK&lt;&#x2F;code&gt; 标志的 &lt;code&gt;accept4&lt;&#x2F;code&gt; 系统调用，将套接字的文件描述符设置为非阻塞模式。随后，系统会创建若干描述符以整合 Go 运行时的 netpoll。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;创建一个 &lt;code&gt;net.netFD&lt;&#x2F;code&gt; 实例来封装套接字的文件描述符。这个结构体为基于底层内核文件描述符执行网络操作提供了更高层的抽象。当初始化 &lt;code&gt;net.netFD&lt;&#x2F;code&gt; 后，会调用 &lt;code&gt;epoll_create&lt;&#x2F;code&gt; 系统调用创建一个 &lt;code&gt;epoll&lt;&#x2F;code&gt; 实例。这个 &lt;code&gt;epoll&lt;&#x2F;code&gt; 实例在 &lt;code&gt;poll_runtime_pollServerInit&lt;&#x2F;code&gt; 函数中初始化，且该函数被封装在 &lt;code&gt;sync.Once&lt;&#x2F;code&gt; 中，以确保它只执行一次。由于 &lt;code&gt;sync.Once&lt;&#x2F;code&gt; 的保证，在一个 Go 进程中只存在单个 &lt;code&gt;epoll&lt;&#x2F;code&gt; 实例，并且该实例在进程整个生命周期内被使用。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;poll_runtime_pollOpen&lt;&#x2F;code&gt; 函数中，Go 运行时会分配一个 &lt;code&gt;runtime.pollDesc&lt;&#x2F;code&gt; 实例，包含调度信息和对参与 I&#x2F;O 操作的 goroutine 的引用。然后将套接字的文件描述符以兴趣列表的形式使用 &lt;code&gt;epoll_ctl&lt;&#x2F;code&gt; 系统调用注册到 &lt;code&gt;epoll&lt;&#x2F;code&gt;，调用参数为 &lt;code&gt;EPOLL_CTL_ADD&lt;&#x2F;code&gt;。由于 &lt;code&gt;epoll&lt;&#x2F;code&gt; 监视的是文件描述符而非 goroutine，&lt;code&gt;epoll_ctl&lt;&#x2F;code&gt; 还会将文件描述符与 &lt;code&gt;runtime.pollDesc&lt;&#x2F;code&gt; 实例关联，从而让 Go 调度器在 I&#x2F;O 就绪时能识别并恢复相应的 goroutine。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;创建一个 &lt;code&gt;poll.FD&lt;&#x2F;code&gt; 实例以支持带轮询的读写操作。它通过 &lt;code&gt;poll.pollDesc&lt;&#x2F;code&gt; 持有对 &lt;code&gt;runtime.pollDesc&lt;&#x2F;code&gt; 的间接引用，&lt;code&gt;poll.pollDesc&lt;&#x2F;code&gt; 只是一个简单的包装器。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;⚠️ Go 在使用单个 &lt;code&gt;epoll&lt;&#x2F;code&gt; 实例时存在问题，具体情况可见这个公开问题讨论。围绕 Go 是否应该使用单个或多个 &lt;code&gt;epoll&lt;&#x2F;code&gt; 实例，甚至是否采用其他 I&#x2F;O 多路复用模型如 &lt;code&gt;io_uring&lt;&#x2F;code&gt;，社区中仍有讨论。&lt;&#x2F;p&gt;
&lt;p&gt;基于该模型在网络 I&#x2F;O 方面的成功，Go 也利用了 &lt;code&gt;epoll&lt;&#x2F;code&gt; 来处理文件 I&#x2F;O。一旦文件被打开，会调用 &lt;code&gt;syscall.SetNonblock&lt;&#x2F;code&gt; 函数将文件描述符设置为非阻塞模式。随后，&lt;code&gt;poll.FD&lt;&#x2F;code&gt;、&lt;code&gt;poll.pollDesc&lt;&#x2F;code&gt; 和 &lt;code&gt;runtime.pollDesc&lt;&#x2F;code&gt; 实例被初始化，用以将文件描述符注册到 &lt;code&gt;epoll&lt;&#x2F;code&gt; 的兴趣列表中，从而实现文件 I&#x2F;O 的多路复用。&lt;&#x2F;p&gt;
&lt;p&gt;下图展示了这些描述符之间的关系。同时，&lt;code&gt;net.netFD&lt;&#x2F;code&gt;、&lt;code&gt;os.File&lt;&#x2F;code&gt;、&lt;code&gt;poll.FD&lt;&#x2F;code&gt; 和 &lt;code&gt;poll.pollDesc&lt;&#x2F;code&gt; 是用 Go 代码（具体来说是在 Go 标准库中）实现的，而 &lt;code&gt;runtime.pollDesc&lt;&#x2F;code&gt; 则存在于 Go 运行时本身。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;C7XUXTx.png&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lun-xun-wen-jian-miao-shu-fu&quot;&gt;轮询文件描述符&lt;a class=&quot;zola-anchor&quot; href=&quot;#lun-xun-wen-jian-miao-shu-fu&quot; aria-label=&quot;Anchor link for: lun-xun-wen-jian-miao-shu-fu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;当一个 goroutine 从套接字或文件读取时，最终会调用 &lt;code&gt;poll.FD&lt;&#x2F;code&gt; 的 &lt;code&gt;Read&lt;&#x2F;code&gt; 方法。在该方法中，goroutine 会调用 &lt;code&gt;read&lt;&#x2F;code&gt; 系统调用从文件描述符获取可用数据。如果 I&#x2F;O 数据尚不可用，即返回 &lt;code&gt;EAGAIN&lt;&#x2F;code&gt; 错误，Go 运行时会调用 &lt;code&gt;poll_runtime_pollWait&lt;&#x2F;code&gt; 方法将该 goroutine 挂起。写入套接字或文件时的行为类似，主要区别是 &lt;code&gt;Read&lt;&#x2F;code&gt; 被替换为 &lt;code&gt;Write&lt;&#x2F;code&gt;，&lt;code&gt;read&lt;&#x2F;code&gt; 系统调用被替换为 &lt;code&gt;write&lt;&#x2F;code&gt;。当 goroutine 处于 &lt;code&gt;waiting&lt;&#x2F;code&gt; 状态时，netpoll 的职责是在线程文件描述符准备好进行 I&#x2F;O 时，将该 goroutine 呈现给 Go 运行时，这样它才能被恢复执行。&lt;&#x2F;p&gt;
&lt;p&gt;在 Go 运行时中，netpoll 其实只是同名的一个函数。在 netpoll 函数中，调用 &lt;code&gt;epoll_wait&lt;&#x2F;code&gt; 系统调用监视最多 128 个文件描述符，在指定时间内等待事件发生。该系统调用会返回先前注册（如前面章节所述）的、对应每个准备就绪的文件描述符的 &lt;code&gt;runtime.pollDesc&lt;&#x2F;code&gt; 实例。最后，netpoll 从 &lt;code&gt;runtime.pollDesc&lt;&#x2F;code&gt; 中提取 goroutine 的引用，并将它们交给 Go 运行时。&lt;&#x2F;p&gt;
&lt;p&gt;那么，netpoll 函数究竟何时被调用？当线程寻找可运行的 goroutine 来执行时触发，如调度循环（schedule loop）所述。根据 &lt;code&gt;findRunnable&lt;&#x2F;code&gt; 函数，只有当当前 &lt;code&gt;P&lt;&#x2F;code&gt; 的本地运行队列和全局运行队列都没有可运行的 goroutine 时，Go 运行时才会调用 netpoll。这意味着，即使文件描述符已经准备好进行 I&#x2F;O，goroutine 也不一定会立即被唤醒。&lt;&#x2F;p&gt;
&lt;p&gt;如前所述，netpoll 可以阻塞指定时间，这由 &lt;code&gt;delay&lt;&#x2F;code&gt; 参数决定。如果 &lt;code&gt;delay&lt;&#x2F;code&gt; 为正，则阻塞指定的纳秒数；如果 &lt;code&gt;delay&lt;&#x2F;code&gt; 为负，则阻塞直到有 I&#x2F;O 事件准备好；如果 &lt;code&gt;delay&lt;&#x2F;code&gt; 为零，则立即返回当前已就绪的所有 I&#x2F;O 事件。在 &lt;code&gt;findRunnable&lt;&#x2F;code&gt; 函数中，&lt;code&gt;delay&lt;&#x2F;code&gt; 参数传递为 0，表示如果有一个 goroutine 正等待 I&#x2F;O，调度器就可以安排另一个 goroutine 在同一个内核线程上运行。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zhu-xiao-wen-jian-miao-shu-fu&quot;&gt;注销文件描述符&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhu-xiao-wen-jian-miao-shu-fu&quot; aria-label=&quot;Anchor link for: zhu-xiao-wen-jian-miao-shu-fu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;如上所述，&lt;code&gt;epoll&lt;&#x2F;code&gt; 实例最多监视 128 个文件描述符。因此，当文件描述符不再需要时，注销它们非常重要，否则可能导致某些 goroutine 饥饿。当文件或网络连接不再使用时，应通过调用其 &lt;code&gt;Close&lt;&#x2F;code&gt; 方法关闭它。&lt;&#x2F;p&gt;
&lt;p&gt;在底层，会调用 &lt;code&gt;poll.FD&lt;&#x2F;code&gt; 的 &lt;code&gt;destroy&lt;&#x2F;code&gt; 方法。该方法最终调用 Go 运行时的 &lt;code&gt;poll_runtime_pollClose&lt;&#x2F;code&gt; 函数，通过 &lt;code&gt;epoll_ctl&lt;&#x2F;code&gt; 系统调用和 &lt;code&gt;EPOLL_CTL_DEL&lt;&#x2F;code&gt; 操作，将文件描述符从 &lt;code&gt;epoll&lt;&#x2F;code&gt; 的兴趣列表中注销。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zheng-ti-liu-cheng&quot;&gt;整体流程&lt;a class=&quot;zola-anchor&quot; href=&quot;#zheng-ti-liu-cheng&quot; aria-label=&quot;Anchor link for: zheng-ti-liu-cheng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;下图展示了 netpoll 在 Go 运行时中处理文件 I&#x2F;O 的完整过程。网络 I&#x2F;O 的流程类似，只是在此基础上增加了用于接受连接并关闭连接的 TCP 监听器。为了简化起见，诸如 &lt;code&gt;sysmon&lt;&#x2F;code&gt; 和其他空闲处理器 &lt;code&gt;P&lt;&#x2F;code&gt; 等组件未包含在图中。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;iGrWFbd.png&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;la-ji-hui-shou-qi&quot;&gt;垃圾回收器&lt;a class=&quot;zola-anchor&quot; href=&quot;#la-ji-hui-shou-qi&quot; aria-label=&quot;Anchor link for: la-ji-hui-shou-qi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;你可能知道 Go 包含了一个垃圾回收器（GC）来自动回收未使用对象的内存。然而，如“程序启动”部分所述，当程序启动时，初始并没有可用的线程来运行 GC。那么，GC 实际上是在哪里运行的呢？&lt;&#x2F;p&gt;
&lt;p&gt;在回答这个问题之前，我们先快速了解一下垃圾回收的工作原理。Go 使用的是追踪式垃圾回收器，它通过遍历从一组根引用出发的已分配对象图来识别存活和死亡对象。从根对象可达的视为存活；不可达的则视为死亡，可以回收。&lt;&#x2F;p&gt;
&lt;p&gt;Go 的 GC 实现了支持弱引用的三色标记算法。这种设计允许垃圾回收器与程序并发运行，显著减少“停止世界”（STW）暂停时间，并提升整体性能。&lt;&#x2F;p&gt;
&lt;p&gt;一次 Go 垃圾回收周期可以分为四个阶段：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;第一次 STW：暂停整个进程，使所有处理器 &lt;code&gt;P&lt;&#x2F;code&gt; 都能进入安全点。&lt;&#x2F;li&gt;
&lt;li&gt;标记阶段：GC goroutine 短暂占用处理器 &lt;code&gt;P&lt;&#x2F;code&gt; 来标记可达对象。&lt;&#x2F;li&gt;
&lt;li&gt;第二次 STW：再次暂停进程，允许 GC 完成标记阶段。&lt;&#x2F;li&gt;
&lt;li&gt;清扫阶段：恢复进程运行，在后台回收不可达对象的内存。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;需要注意的是，在第 2 步，垃圾回收工作 goroutine 会与普通 goroutine 在同一处理器 &lt;code&gt;P&lt;&#x2F;code&gt; 上并发运行。&lt;code&gt;findRunnable&lt;&#x2F;code&gt; 函数（见“查找可运行的 Goroutine”部分）不仅寻找普通 goroutine，也会寻找 GC goroutine（步骤 1 和 2）。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;chang-yong-han-shu&quot;&gt;常用函数&lt;a class=&quot;zola-anchor&quot; href=&quot;#chang-yong-han-shu&quot; aria-label=&quot;Anchor link for: chang-yong-han-shu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;huo-qu-goroutine-getg&quot;&gt;获取 Goroutine：&lt;code&gt;getg&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#huo-qu-goroutine-getg&quot; aria-label=&quot;Anchor link for: huo-qu-goroutine-getg&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;在 Go 运行时，有一个常用函数用于获取当前内核线程中正在运行的 goroutine，即 &lt;code&gt;getg()&lt;&#x2F;code&gt;。查看源码你会发现该函数没有具体实现。这是因为在编译时，编译器会将对该函数的调用重写为从线程本地存储（thread-local storage，TLS）或寄存器中获取当前 goroutine 的指令。&lt;&#x2F;p&gt;
&lt;p&gt;那么，当前 goroutine 何时会存储到线程本地存储中以供后续检索呢？这发生在 goroutine 的上下文切换过程中，具体在 &lt;code&gt;gogo&lt;&#x2F;code&gt; 函数中执行，该函数由 &lt;code&gt;execute&lt;&#x2F;code&gt; 调用。当信号处理程序被触发时，也会在 &lt;code&gt;sigtrampgo&lt;&#x2F;code&gt; 函数中进行类似操作。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;goroutine-gua-qi-gopark&quot;&gt;Goroutine 挂起：&lt;code&gt;gopark&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#goroutine-gua-qi-gopark&quot; aria-label=&quot;Anchor link for: goroutine-gua-qi-gopark&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;这是 Go 运行时中一个常用的过程，用于将当前 goroutine 转换为 &lt;code&gt;waiting&lt;&#x2F;code&gt; 状态，并调度另一个 goroutine 运行。下面的代码片段突出展示了它的一些关键点。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;gopark&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;unlockf&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;g&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;unsafe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;mp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;waitunlockf&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;unlockf&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-function z-go&quot;&gt;releasem&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;mp&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-function z-go&quot;&gt;mcall&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;park_m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在 &lt;code&gt;releasem&lt;&#x2F;code&gt; 函数中，会将该 goroutine 的 &lt;code&gt;stackguard0&lt;&#x2F;code&gt; 设置为 &lt;code&gt;stackPreempt&lt;&#x2F;code&gt;，以触发最终的协作式抢占。控制权随后转移给同一线程下当前运行该 goroutine 的 &lt;code&gt;go&lt;&#x2F;code&gt; 系统 goroutine，进而调用 &lt;code&gt;park_m&lt;&#x2F;code&gt; 函数。&lt;&#x2F;p&gt;
&lt;p&gt;在 &lt;code&gt;park_m&lt;&#x2F;code&gt; 中，goroutine 的状态被设为 &lt;code&gt;waiting&lt;&#x2F;code&gt;，并且该 goroutine 与线程 &lt;code&gt;M&lt;&#x2F;code&gt; 的关联被解除。此外，&lt;code&gt;gopark&lt;&#x2F;code&gt; 接收一个 &lt;code&gt;unlockf&lt;&#x2F;code&gt; 回调函数，该函数会在 &lt;code&gt;park_m&lt;&#x2F;code&gt; 中执行。如果 &lt;code&gt;unlockf&lt;&#x2F;code&gt; 返回 &lt;code&gt;false&lt;&#x2F;code&gt;，则挂起的 goroutine 会立即重新变为可运行状态，并通过调用 &lt;code&gt;execute&lt;&#x2F;code&gt; 在同一个线程 &lt;code&gt;M&lt;&#x2F;code&gt; 上重新调度。否则，线程 &lt;code&gt;M&lt;&#x2F;code&gt; 会进入调度循环（schedule loop），选择一个 goroutine 并执行它。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;qi-dong-xian-cheng-startm&quot;&gt;启动线程：&lt;code&gt;startm&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#qi-dong-xian-cheng-startm&quot; aria-label=&quot;Anchor link for: qi-dong-xian-cheng-startm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;这个函数负责调度一个线程 &lt;code&gt;M&lt;&#x2F;code&gt; 来运行指定的处理器 &lt;code&gt;P&lt;&#x2F;code&gt;。下图展示了该函数的流程，其中 &lt;code&gt;M1&lt;&#x2F;code&gt; 线程是 &lt;code&gt;M2&lt;&#x2F;code&gt; 线程的父线程。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;wggGK3T.png&quot; alt=&quot;img&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;如果 &lt;code&gt;P&lt;&#x2F;code&gt; 为 &lt;code&gt;nil&lt;&#x2F;code&gt;，函数会尝试从全局空闲处理器列表中获取一个空闲处理器。如果没有空闲处理器可用，函数会直接返回——这表明最大数量的活跃处理器已被使用，且无法创建或激活额外的线程 &lt;code&gt;M&lt;&#x2F;code&gt;。如果找到空闲处理器（或者参数中已传入 &lt;code&gt;P&lt;&#x2F;code&gt;），函数将创建一个新线程 &lt;code&gt;M1&lt;&#x2F;code&gt;（如果没有空闲线程）或者唤醒一个已有的空闲线程，使其运行处理器 &lt;code&gt;P&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;唤醒后，现有线程 &lt;code&gt;M&lt;&#x2F;code&gt; 会继续进入调度循环（schedule loop）。如果创建了新线程，则通过 &lt;code&gt;clone&lt;&#x2F;code&gt; 系统调用完成，入口函数为 &lt;code&gt;mstart&lt;&#x2F;code&gt;。随后，&lt;code&gt;mstart&lt;&#x2F;code&gt; 会转入调度循环，寻找可运行的 goroutine 并执行。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ting-zhi-xian-cheng-stopm&quot;&gt;停止线程：&lt;code&gt;stopm&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#ting-zhi-xian-cheng-stopm&quot; aria-label=&quot;Anchor link for: ting-zhi-xian-cheng-stopm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;该函数将线程 &lt;code&gt;M&lt;&#x2F;code&gt; 添加到空闲列表，并使其进入休眠状态。&lt;code&gt;stopm&lt;&#x2F;code&gt; 直到线程 &lt;code&gt;M&lt;&#x2F;code&gt; 被另一个线程唤醒才会返回，通常是在创建新 goroutine 时被唤醒，如“唤醒处理器”部分所述。这个过程通过 &lt;code&gt;futex&lt;&#x2F;code&gt; 系统调用实现，使线程 &lt;code&gt;M&lt;&#x2F;code&gt; 在等待时不会占用 CPU 时间。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;chu-li-qi-yi-jiao-handoffp&quot;&gt;处理器移交：&lt;code&gt;handoffp&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#chu-li-qi-yi-jiao-handoffp&quot; aria-label=&quot;Anchor link for: chu-li-qi-yi-jiao-handoffp&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;handoffp&lt;&#x2F;code&gt; 负责将处理器 &lt;code&gt;P&lt;&#x2F;code&gt; 的所有权从在系统调用中阻塞的线程 &lt;code&gt;M&lt;&#x2F;code&gt; 转移到另一个线程 &lt;code&gt;M1&lt;&#x2F;code&gt;。处理器 &lt;code&gt;P&lt;&#x2F;code&gt; 会与 &lt;code&gt;M1&lt;&#x2F;code&gt; 关联，以便通过调用 &lt;code&gt;startm&lt;&#x2F;code&gt; 在某些条件下推进运行：如果全局运行队列非空、本地运行队列非空、存在追踪工作或垃圾回收任务，或者当前没有线程处理网络轮询。如果以上条件均不满足，处理器 &lt;code&gt;P&lt;&#x2F;code&gt; 会被放回处理器空闲列表。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;go-yun-xing-shi-api&quot;&gt;Go 运行时 API&lt;a class=&quot;zola-anchor&quot; href=&quot;#go-yun-xing-shi-api&quot; aria-label=&quot;Anchor link for: go-yun-xing-shi-api&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Go 运行时提供了多个 API，用于与调度器和 goroutine 交互。同时，这些 API 也允许 Go 程序员根据应用的具体需求调优调度器以及诸如垃圾回收器等组件。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gomaxprocs&quot;&gt;GOMAXPROCS&lt;a class=&quot;zola-anchor&quot; href=&quot;#gomaxprocs&quot; aria-label=&quot;Anchor link for: gomaxprocs&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;该函数用于设置 Go 运行时中的处理器数量 &lt;code&gt;P&lt;&#x2F;code&gt;，从而控制 Go 程序的并行度。&lt;code&gt;GOMAXPROCS&lt;&#x2F;code&gt; 的默认值是 &lt;code&gt;runtime.NumCPU&lt;&#x2F;code&gt; 函数的返回值，该函数查询操作系统分配给 Go 进程的 CPU 数量。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;GOMAXPROCS&lt;&#x2F;code&gt; 的默认值在某些情况下可能存在问题，特别是在容器化环境中，有关详情可以参考这篇优秀的文章。目前有一个持续的提案，计划让 &lt;code&gt;GOMAXPROCS&lt;&#x2F;code&gt; 尊重 CPU cgroup 限额，以提升其在此类环境中的表现。在未来的 Go 版本中，&lt;code&gt;GOMAXPROCS&lt;&#x2F;code&gt; 可能会变得不再必要，就像官方文档中所述：“随着调度器的改进，这个调用将会被废弃。”&lt;&#x2F;p&gt;
&lt;p&gt;某些 I&#x2F;O 受限的程序可能会从比默认值更高的处理器数量 &lt;code&gt;P&lt;&#x2F;code&gt; 中受益。例如，Dgraph 数据库将 &lt;code&gt;GOMAXPROCS&lt;&#x2F;code&gt; 硬编码为 128，以便调度更多的 I&#x2F;O 操作。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;goexit&quot;&gt;Goexit&lt;a class=&quot;zola-anchor&quot; href=&quot;#goexit&quot; aria-label=&quot;Anchor link for: goexit&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;该函数用于优雅地终止当前 goroutine。所有延迟调用（defer）会在 goroutine 终止前执行。程序会继续执行其他 goroutine。如果所有其他 goroutine 都退出，程序则会崩溃。&lt;code&gt;Goexit&lt;&#x2F;code&gt; 更适合用于测试场景，而非实际应用，比如在测试用例需要提前中止（例如前提条件未满足）但仍希望执行延迟清理时使用。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jie-lun&quot;&gt;结论&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-lun&quot; aria-label=&quot;Anchor link for: jie-lun&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Go 调度器是一个强大且高效的系统，通过 goroutine 实现轻量级并发。在这篇博客中，我们探讨了它的发展历程——从最初的模型到 GMP 架构——以及关键组件，如 goroutine 的创建、抢占、系统调用处理和网络轮询集成。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;nghiant3223.github.io&#x2F;2025&#x2F;04&#x2F;15&#x2F;go-scheduler.html&lt;&#x2F;li&gt;
&lt;li&gt;kelche.co. &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.kelche.co&#x2F;blog&#x2F;go&#x2F;golang-scheduling&quot;&gt;&lt;em&gt;Go Scheduling&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;unskilled.blog. &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;unskilled.blog&#x2F;posts&#x2F;preemption-in-go-an-introduction&#x2F;&quot;&gt;&lt;em&gt;Preemption in Go&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Ian Lance Taylor. &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;groups.google.com&#x2F;g&#x2F;golang-nuts&#x2F;c&#x2F;JCKWH8fap9o&quot;&gt;&lt;em&gt;What is system stack?&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;[6], [7] Michael Kerrisk. &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;man7.org&#x2F;tlpi&#x2F;&quot;&gt;&lt;em&gt;The Linux Programming Interface&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;[8], [9], [10] W. Richard Stevens. &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;UNIX-Network-Programming-Richard-Stevens&#x2F;dp&#x2F;0139498761&quot;&gt;&lt;em&gt;Unix Network Programming&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;zhuanlan.zhihu.com. &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;zhuanlan.zhihu.com&#x2F;p&#x2F;436925356&quot;&gt;&lt;em&gt;Golang program startup process analysis&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Madhav Jivrajani. &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=wQpC99Xu1U4&amp;amp;t=2375s&amp;amp;ab_channel=GopherAcademy&quot;&gt;&lt;em&gt;GopherCon 2021: Queues, Fairness, and The Go Scheduler&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;[1], [2], [3] Abraham Silberschatz, Peter B. Galvin, Greg Gagne. &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;Operating-System-Concepts-Abraham-Silberschatz&#x2F;dp&#x2F;1119800366&#x2F;ref=zg-te-pba_d_sccl_3_1&#x2F;138-7692107-2007040&quot;&gt;&lt;em&gt;Operating System Concepts&lt;&#x2F;em&gt;&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Japanese | これから vs それから vs 今から</title>
          <pubDate>Thu, 10 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-10-japanese-kerekara-imakara-sorekara/</link>
          <guid>https://inasa.dev/posts/25-07-10-japanese-kerekara-imakara-sorekara/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-10-japanese-kerekara-imakara-sorekara/">&lt;h2 id=&quot;ji-ben-han-yi&quot;&gt;基本含义&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-ben-han-yi&quot; aria-label=&quot;Anchor link for: ji-ben-han-yi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;korekara&quot;&gt;これから&lt;a class=&quot;zola-anchor&quot; href=&quot;#korekara&quot; aria-label=&quot;Anchor link for: korekara&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&quot;从现在开始，今后，以后&quot;&lt;&#x2F;li&gt;
&lt;li&gt;表示从现在这个时点向未来延续&lt;&#x2F;li&gt;
&lt;li&gt;时间跨度较长，带有持续性&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;sorekara&quot;&gt;それから&lt;a class=&quot;zola-anchor&quot; href=&quot;#sorekara&quot; aria-label=&quot;Anchor link for: sorekara&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&quot;然后，接着，之后&quot;&lt;&#x2F;li&gt;
&lt;li&gt;表示时间上的先后顺序&lt;&#x2F;li&gt;
&lt;li&gt;连接两个动作或事件&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;jin-kara&quot;&gt;今から&lt;a class=&quot;zola-anchor&quot; href=&quot;#jin-kara&quot; aria-label=&quot;Anchor link for: jin-kara&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&quot;从现在开始，马上&quot;&lt;&#x2F;li&gt;
&lt;li&gt;强调立即性和紧迫感&lt;&#x2F;li&gt;
&lt;li&gt;时间跨度较短，即时行动&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;xiang-xi-qu-bie&quot;&gt;详细区别&lt;a class=&quot;zola-anchor&quot; href=&quot;#xiang-xi-qu-bie&quot; aria-label=&quot;Anchor link for: xiang-xi-qu-bie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1-shi-jian-gai-nian&quot;&gt;1. 时间概念&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-shi-jian-gai-nian&quot; aria-label=&quot;Anchor link for: 1-shi-jian-gai-nian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;これから&lt;&#x2F;strong&gt;（未来持续）&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;これから頑張ります。（今后会努力）&lt;&#x2F;li&gt;
&lt;li&gt;これから雨が降るでしょう。（接下来会下雨吧）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;それから&lt;&#x2F;strong&gt;（顺序连接）&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;朝ごはんを食べて、&lt;strong&gt;それから&lt;&#x2F;strong&gt;学校に行きます。
（吃完早饭，然后去学校）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;今から&lt;&#x2F;strong&gt;（立即行动）&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;今から出かけます。（现在就出门）&lt;&#x2F;li&gt;
&lt;li&gt;今から始めましょう。（现在就开始吧）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;2-shi-yong-chang-jing&quot;&gt;2. 使用场景&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-shi-yong-chang-jing&quot; aria-label=&quot;Anchor link for: 2-shi-yong-chang-jing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;korekara-1&quot;&gt;これから&lt;a class=&quot;zola-anchor&quot; href=&quot;#korekara-1&quot; aria-label=&quot;Anchor link for: korekara-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;计划、决心&lt;&#x2F;strong&gt;：これから日本語を勉強します&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;预测、推测&lt;&#x2F;strong&gt;：これから寒くなります&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;人生规划&lt;&#x2F;strong&gt;：これからの人生&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;sorekara-1&quot;&gt;それから&lt;a class=&quot;zola-anchor&quot; href=&quot;#sorekara-1&quot; aria-label=&quot;Anchor link for: sorekara-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;叙述顺序&lt;&#x2F;strong&gt;：起きて、洗顔して、&lt;strong&gt;それから&lt;&#x2F;strong&gt;朝食&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;补充说明&lt;&#x2F;strong&gt;：映画を見ました。&lt;strong&gt;それから&lt;&#x2F;strong&gt;買い物もしました&lt;&#x2F;li&gt;
&lt;li&gt;对话中的转折**：そうですね。**それから...&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;jin-kara-1&quot;&gt;今から&lt;a class=&quot;zola-anchor&quot; href=&quot;#jin-kara-1&quot; aria-label=&quot;Anchor link for: jin-kara-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;即时行动&lt;&#x2F;strong&gt;：今から会議です&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;紧急情况&lt;&#x2F;strong&gt;：今から病院に行きます&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;约定时间&lt;&#x2F;strong&gt;：今から30分後に会いましょう&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;dui-bi-li-ju&quot;&gt;对比例句&lt;a class=&quot;zola-anchor&quot; href=&quot;#dui-bi-li-ju&quot; aria-label=&quot;Anchor link for: dui-bi-li-ju&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;tong-yi-qing-kuang-de-bu-tong-biao-da&quot;&gt;同一情况的不同表达&lt;a class=&quot;zola-anchor&quot; href=&quot;#tong-yi-qing-kuang-de-bu-tong-biao-da&quot; aria-label=&quot;Anchor link for: tong-yi-qing-kuang-de-bu-tong-biao-da&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;场景：准备学习&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;これから&lt;&#x2F;strong&gt;勉強します。（今后要学习→长期计划）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;今から&lt;&#x2F;strong&gt;勉強します。（现在就学习→立即行动）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;场景：叙述一天的活动&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;朝起きて、&lt;strong&gt;それから&lt;&#x2F;strong&gt;シャワーを浴びて、&lt;strong&gt;それから&lt;&#x2F;strong&gt;朝食を食べました。
（早上起床，然后洗澡，然后吃早饭）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;yu-fa-da-pei&quot;&gt;语法搭配&lt;a class=&quot;zola-anchor&quot; href=&quot;#yu-fa-da-pei&quot; aria-label=&quot;Anchor link for: yu-fa-da-pei&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;korekara-2&quot;&gt;これから&lt;a class=&quot;zola-anchor&quot; href=&quot;#korekara-2&quot; aria-label=&quot;Anchor link for: korekara-2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;これから + 动词：これから行きます&lt;&#x2F;li&gt;
&lt;li&gt;これからの + 名词：これからの予定&lt;&#x2F;li&gt;
&lt;li&gt;これから先：今後&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;sorekara-2&quot;&gt;それから&lt;a class=&quot;zola-anchor&quot; href=&quot;#sorekara-2&quot; aria-label=&quot;Anchor link for: sorekara-2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;动词て形 + それから：食べて&lt;strong&gt;それから&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;句子 + それから + 句子&lt;&#x2F;li&gt;
&lt;li&gt;それからというもの：从那以后&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;jin-kara-2&quot;&gt;今から&lt;a class=&quot;zola-anchor&quot; href=&quot;#jin-kara-2&quot; aria-label=&quot;Anchor link for: jin-kara-2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;今から + 时间：今から1時間後&lt;&#x2F;li&gt;
&lt;li&gt;今から + 动词：今から始める&lt;&#x2F;li&gt;
&lt;li&gt;今からでも：即使是现在&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;ji-yi-ji-qiao&quot;&gt;记忆技巧&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-yi-ji-qiao&quot; aria-label=&quot;Anchor link for: ji-yi-ji-qiao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;korekara-3&quot;&gt;これから&lt;a class=&quot;zola-anchor&quot; href=&quot;#korekara-3&quot; aria-label=&quot;Anchor link for: korekara-3&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;これ&lt;&#x2F;strong&gt;（这个）&lt;strong&gt;から&lt;&#x2F;strong&gt;（从）= 从这个时间点开始&lt;&#x2F;li&gt;
&lt;li&gt;重点：&lt;strong&gt;持续性的未来&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;sorekara-3&quot;&gt;それから&lt;a class=&quot;zola-anchor&quot; href=&quot;#sorekara-3&quot; aria-label=&quot;Anchor link for: sorekara-3&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;それ&lt;&#x2F;strong&gt;（那个）&lt;strong&gt;から&lt;&#x2F;strong&gt;（从）= 从那个动作之后&lt;&#x2F;li&gt;
&lt;li&gt;重点：&lt;strong&gt;时间顺序的连接&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;jin-kara-3&quot;&gt;今から&lt;a class=&quot;zola-anchor&quot; href=&quot;#jin-kara-3&quot; aria-label=&quot;Anchor link for: jin-kara-3&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;今&lt;&#x2F;strong&gt;（现在）&lt;strong&gt;から&lt;&#x2F;strong&gt;（从）= 从现在开始&lt;&#x2F;li&gt;
&lt;li&gt;重点：&lt;strong&gt;立即性和紧迫感&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;chang-jian-cuo-wu&quot;&gt;常见错误&lt;a class=&quot;zola-anchor&quot; href=&quot;#chang-jian-cuo-wu&quot; aria-label=&quot;Anchor link for: chang-jian-cuo-wu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;❌ 错误用法：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;それから頑張ります。（应该用これから）&lt;&#x2F;li&gt;
&lt;li&gt;これから映画を見て、買い物をしました。（应该用それから）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;✅ 正确用法：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;これから&lt;&#x2F;strong&gt;頑張ります。&lt;&#x2F;li&gt;
&lt;li&gt;映画を見て、&lt;strong&gt;それから&lt;&#x2F;strong&gt;買い物をしました。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;记忆口诀：これから未来，それから顺序，今から立即！&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Japanese | 意志性动词与非意志性动词</title>
          <pubDate>Thu, 10 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-10-japanese-volitional-verbs-non-volitional-verbs/</link>
          <guid>https://inasa.dev/posts/25-07-10-japanese-volitional-verbs-non-volitional-verbs/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-10-japanese-volitional-verbs-non-volitional-verbs/">&lt;h2 id=&quot;yi-zhi-xing-dong-ci-volitional-verbs&quot;&gt;意志性动词 (Volitional Verbs)&lt;a class=&quot;zola-anchor&quot; href=&quot;#yi-zhi-xing-dong-ci-volitional-verbs&quot; aria-label=&quot;Anchor link for: yi-zhi-xing-dong-ci-volitional-verbs&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;意志性动词是指表示主体能够通过自己的意志来控制的动作。简单来说，就是&quot;可以决定去做&quot;的动作。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;例如：&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;食べる (吃)&lt;&#x2F;li&gt;
&lt;li&gt;行く (去)&lt;&#x2F;li&gt;
&lt;li&gt;勉強する (学习)&lt;&#x2F;li&gt;
&lt;li&gt;読む (读)&lt;&#x2F;li&gt;
&lt;li&gt;買う (买)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;fei-yi-zhi-xing-dong-ci-non-volitional-verbs&quot;&gt;非意志性动词 (Non-volitional Verbs)&lt;a class=&quot;zola-anchor&quot; href=&quot;#fei-yi-zhi-xing-dong-ci-non-volitional-verbs&quot; aria-label=&quot;Anchor link for: fei-yi-zhi-xing-dong-ci-non-volitional-verbs&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;非意志性动词是指表示非主观意愿的状态、现象或发生的事情，即不受主体意志控制的动作或状态。简单来说，就是&quot;无法通过意志控制&quot;的事情。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;例如：&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;分かる (明白，理解)&lt;&#x2F;li&gt;
&lt;li&gt;忘れる (忘记)&lt;&#x2F;li&gt;
&lt;li&gt;見つかる (被发现)&lt;&#x2F;li&gt;
&lt;li&gt;困る (感到困扰)&lt;&#x2F;li&gt;
&lt;li&gt;驚く (吃惊)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;yu-fa-ying-yong-qu-bie&quot;&gt;语法应用区别&lt;a class=&quot;zola-anchor&quot; href=&quot;#yu-fa-ying-yong-qu-bie&quot; aria-label=&quot;Anchor link for: yu-fa-ying-yong-qu-bie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;这一区分在日语语法中非常重要，会影响多种语法形式：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;命令形和禁止形&lt;&#x2F;strong&gt;：通常只有意志性动词才能使用命令形，因为你不能命令某人&quot;理解&quot;或&quot;忘记&quot;等非自主行为。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;~ようと思います&lt;&#x2F;strong&gt; (打算做某事)：只能与意志性动词连用，因为你不能&quot;打算明白&quot;或&quot;打算忘记&quot;。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;~てください&lt;&#x2F;strong&gt; (请做某事)：一般只用于意志性动词。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可能形态的表达方式&lt;&#x2F;strong&gt;：非意志性动词通常不使用可能形，因为它们本身就表示一种可能性或无法控制的事件。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</description>
      </item>
      <item>
          <title>Japanese | 分かりません 和 知りません 的详细区别</title>
          <pubDate>Thu, 10 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-10-japanese-wakarimasenn-shirimasenn/</link>
          <guid>https://inasa.dev/posts/25-07-10-japanese-wakarimasenn-shirimasenn/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-10-japanese-wakarimasenn-shirimasenn/">&lt;h2 id=&quot;1-ji-ben-han-yi-qu-bie&quot;&gt;1. 基本含义区别&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-ji-ben-han-yi-qu-bie&quot; aria-label=&quot;Anchor link for: 1-ji-ben-han-yi-qu-bie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;知りません（知らない）&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;基本意思：不知道（没有知识、信息）&lt;&#x2F;li&gt;
&lt;li&gt;强调：&lt;strong&gt;没有接触过、没有听说过&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;相当于英语的 &quot;I don&#x27;t know&quot; 或 &quot;I have no knowledge of&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;分かりません（分からない）&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;基本意思：不明白、不理解&lt;&#x2F;li&gt;
&lt;li&gt;强调：&lt;strong&gt;理解不了、搞不清楚&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;相当于英语的 &quot;I don&#x27;t understand&quot; 或 &quot;I can&#x27;t figure out&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;2-shi-yong-chang-he-dui-bi&quot;&gt;2. 使用场合对比&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-shi-yong-chang-he-dui-bi&quot; aria-label=&quot;Anchor link for: 2-shi-yong-chang-he-dui-bi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;zhi-rimasen-de-shi-yong-chang-he&quot;&gt;知りません 的使用场合：&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhi-rimasen-de-shi-yong-chang-he&quot; aria-label=&quot;Anchor link for: zhi-rimasen-de-shi-yong-chang-he&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;人名、地名等具体信息&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;田中さんを知りません。（不认识田中先生）&lt;&#x2F;li&gt;
&lt;li&gt;その店を知りません。（不知道那家店）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;事实、消息&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;そのニュースを知りません。（不知道那个新闻）&lt;&#x2F;li&gt;
&lt;li&gt;彼の電話番号を知りません。（不知道他的电话号码）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;fen-karimasen-de-shi-yong-chang-he&quot;&gt;分かりません 的使用场合：&lt;a class=&quot;zola-anchor&quot; href=&quot;#fen-karimasen-de-shi-yong-chang-he&quot; aria-label=&quot;Anchor link for: fen-karimasen-de-shi-yong-chang-he&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;理解、领悟&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;この問題が分かりません。（这个问题不明白）&lt;&#x2F;li&gt;
&lt;li&gt;先生の説明が分かりません。（老师的说明不理解）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;判断、区别&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;どちらがいいか分かりません。（不知道哪个好）&lt;&#x2F;li&gt;
&lt;li&gt;理由が分かりません。（不明白理由）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;3-ju-ti-li-ju-dui-bi&quot;&gt;3. 具体例句对比&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-ju-ti-li-ju-dui-bi&quot; aria-label=&quot;Anchor link for: 3-ju-ti-li-ju-dui-bi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;情况&lt;&#x2F;th&gt;&lt;th&gt;知りません&lt;&#x2F;th&gt;&lt;th&gt;分かりません&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;不认识人&lt;&#x2F;td&gt;&lt;td&gt;田中さんを&lt;strong&gt;知りません&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;✗&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;不懂数学题&lt;&#x2F;td&gt;&lt;td&gt;✗&lt;&#x2F;td&gt;&lt;td&gt;この問題が&lt;strong&gt;分かりません&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;不知道地址&lt;&#x2F;td&gt;&lt;td&gt;住所を&lt;strong&gt;知りません&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;✗&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;不理解意思&lt;&#x2F;td&gt;&lt;td&gt;✗&lt;&#x2F;td&gt;&lt;td&gt;意味が&lt;strong&gt;分かりません&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;不知道时间&lt;&#x2F;td&gt;&lt;td&gt;時間を&lt;strong&gt;知りません&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;td&gt;時間が&lt;strong&gt;分かりません&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;4-zhong-yao-qu-bie-dian&quot;&gt;4. 重要区别点&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-zhong-yao-qu-bie-dian&quot; aria-label=&quot;Anchor link for: 4-zhong-yao-qu-bie-dian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;zhi-ru-fen-karu-de-guo-cheng&quot;&gt;「知る」→「分かる」的过程：&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhi-ru-fen-karu-de-guo-cheng&quot; aria-label=&quot;Anchor link for: zhi-ru-fen-karu-de-guo-cheng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;知る&lt;&#x2F;strong&gt;：获得信息、知识&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;分かる&lt;&#x2F;strong&gt;：理解、明白已知的信息&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;例子：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;漢字を知っています。（知道这个汉字）&lt;&#x2F;li&gt;
&lt;li&gt;でも、意味が分かりません。（但是不明白意思）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;5-li-mao-cheng-du&quot;&gt;5. 礼貌程度&lt;a class=&quot;zola-anchor&quot; href=&quot;#5-li-mao-cheng-du&quot; aria-label=&quot;Anchor link for: 5-li-mao-cheng-du&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;两者都可以用敬语形式&lt;&#x2F;li&gt;
&lt;li&gt;知りません → &lt;strong&gt;存じません&lt;&#x2F;strong&gt;（更礼貌）&lt;&#x2F;li&gt;
&lt;li&gt;分かりません → &lt;strong&gt;分かりかねます&lt;&#x2F;strong&gt;（更礼貌）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;6-shi-yong-jian-yi&quot;&gt;6. 实用建议&lt;a class=&quot;zola-anchor&quot; href=&quot;#6-shi-yong-jian-yi&quot; aria-label=&quot;Anchor link for: 6-shi-yong-jian-yi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;回答问题时不确定用哪个，可以说：&lt;strong&gt;ちょっと分からないです&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;完全不知道某件事：&lt;strong&gt;全然知りません&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;不理解内容：&lt;strong&gt;よく分かりません&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;记忆方法：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;知る = Know（知道事实）&lt;&#x2F;li&gt;
&lt;li&gt;分かる = Understand（理解含义）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Japanese | わかりました vs わかります</title>
          <pubDate>Thu, 10 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-10-japanese-wakarimashita-wakarimasu/</link>
          <guid>https://inasa.dev/posts/25-07-10-japanese-wakarimashita-wakarimasu/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-10-japanese-wakarimashita-wakarimasu/">&lt;h2 id=&quot;ji-ben-han-yi&quot;&gt;基本含义&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-ben-han-yi&quot; aria-label=&quot;Anchor link for: ji-ben-han-yi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;wakarimasita&quot;&gt;わかりました&lt;a class=&quot;zola-anchor&quot; href=&quot;#wakarimasita&quot; aria-label=&quot;Anchor link for: wakarimasita&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&quot;明白了，懂了&quot;&lt;&#x2F;strong&gt;（过去时）&lt;&#x2F;li&gt;
&lt;li&gt;表示已经理解，理解完成&lt;&#x2F;li&gt;
&lt;li&gt;常用于回应、确认&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;wakarimasu&quot;&gt;わかります&lt;a class=&quot;zola-anchor&quot; href=&quot;#wakarimasu&quot; aria-label=&quot;Anchor link for: wakarimasu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&quot;明白，懂得&quot;&lt;&#x2F;strong&gt;（现在时）&lt;&#x2F;li&gt;
&lt;li&gt;表示理解的能力或状态&lt;&#x2F;li&gt;
&lt;li&gt;常用于表达理解能力&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;shi-tai-qu-bie&quot;&gt;时态区别&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-tai-qu-bie&quot; aria-label=&quot;Anchor link for: shi-tai-qu-bie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;wakarimasita-guo-qu-shi&quot;&gt;&lt;strong&gt;わかりました&lt;&#x2F;strong&gt;（过去时）&lt;a class=&quot;zola-anchor&quot; href=&quot;#wakarimasita-guo-qu-shi&quot; aria-label=&quot;Anchor link for: wakarimasita-guo-qu-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;瞬间完成的理解&lt;&#x2F;li&gt;
&lt;li&gt;对刚才说话的回应&lt;&#x2F;li&gt;
&lt;li&gt;表示&quot;刚刚明白了&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;wakarimasu-xian-zai-shi&quot;&gt;&lt;strong&gt;わかります&lt;&#x2F;strong&gt;（现在时）&lt;a class=&quot;zola-anchor&quot; href=&quot;#wakarimasu-xian-zai-shi&quot; aria-label=&quot;Anchor link for: wakarimasu-xian-zai-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;持续的理解状态&lt;&#x2F;li&gt;
&lt;li&gt;一般性的理解能力&lt;&#x2F;li&gt;
&lt;li&gt;表示&quot;能够理解&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;ju-ti-shi-yong-chang-jing&quot;&gt;具体使用场景&lt;a class=&quot;zola-anchor&quot; href=&quot;#ju-ti-shi-yong-chang-jing&quot; aria-label=&quot;Anchor link for: ju-ti-shi-yong-chang-jing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1-hui-ying-shuo-ming-shi&quot;&gt;1. 回应说明时&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-hui-ying-shuo-ming-shi&quot; aria-label=&quot;Anchor link for: 1-hui-ying-shuo-ming-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;わかりました&lt;&#x2F;strong&gt;（刚明白）&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A: 明日は9時に集合です。&lt;&#x2F;li&gt;
&lt;li&gt;B: わかりました。 ✅
（明白了→对刚才说的话的确认）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;わかります&lt;&#x2F;strong&gt;（能理解）&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A: 明日は9時に集合です。&lt;&#x2F;li&gt;
&lt;li&gt;B: わかります。 ❌
（这样回应不自然）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;2-biao-da-li-jie-neng-li-shi&quot;&gt;2. 表达理解能力时&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-biao-da-li-jie-neng-li-shi&quot; aria-label=&quot;Anchor link for: 2-biao-da-li-jie-neng-li-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;わかります&lt;&#x2F;strong&gt;（能力状态）&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;日本語が&lt;strong&gt;わかります&lt;&#x2F;strong&gt;。✅
（懂日语→持续的能力）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;strong&gt;わかりました&lt;&#x2F;strong&gt;（完成理解）&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;日本語が&lt;strong&gt;わかりました&lt;&#x2F;strong&gt;。△
（刚学会日语→不太自然）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;xiang-xi-dui-bi&quot;&gt;详细对比&lt;a class=&quot;zola-anchor&quot; href=&quot;#xiang-xi-dui-bi&quot; aria-label=&quot;Anchor link for: xiang-xi-dui-bi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;dui-hua-hui-ying&quot;&gt;对话回应&lt;a class=&quot;zola-anchor&quot; href=&quot;#dui-hua-hui-ying&quot; aria-label=&quot;Anchor link for: dui-hua-hui-ying&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;场景&lt;&#x2F;th&gt;&lt;th&gt;わかりました&lt;&#x2F;th&gt;&lt;th&gt;わかります&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;听完说明&lt;&#x2F;td&gt;&lt;td&gt;✅ 最适合&lt;&#x2F;td&gt;&lt;td&gt;❌ 不自然&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;接受指示&lt;&#x2F;td&gt;&lt;td&gt;✅ 最适合&lt;&#x2F;td&gt;&lt;td&gt;❌ 不自然&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;确认理解&lt;&#x2F;td&gt;&lt;td&gt;✅ 最适合&lt;&#x2F;td&gt;&lt;td&gt;❌ 不自然&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;例子：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;老师&lt;&#x2F;strong&gt;：宿題は明日までです。&lt;&#x2F;li&gt;
&lt;li&gt;学生**：**わかりました。 ✅（明白了）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;neng-li-biao-da&quot;&gt;能力表达&lt;a class=&quot;zola-anchor&quot; href=&quot;#neng-li-biao-da&quot; aria-label=&quot;Anchor link for: neng-li-biao-da&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;场景&lt;&#x2F;th&gt;&lt;th&gt;わかります&lt;&#x2F;th&gt;&lt;th&gt;わかりました&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;语言能力&lt;&#x2F;td&gt;&lt;td&gt;✅ 最适合&lt;&#x2F;td&gt;&lt;td&gt;△ 不太自然&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;理解状态&lt;&#x2F;td&gt;&lt;td&gt;✅ 最适合&lt;&#x2F;td&gt;&lt;td&gt;△ 特定情况&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;一般理解&lt;&#x2F;td&gt;&lt;td&gt;✅ 最适合&lt;&#x2F;td&gt;&lt;td&gt;❌ 不合适&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;例子：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;英語が&lt;strong&gt;わかります&lt;&#x2F;strong&gt;。✅（懂英语）&lt;&#x2F;li&gt;
&lt;li&gt;この問題が&lt;strong&gt;わかります&lt;&#x2F;strong&gt;。✅（理解这个问题）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;te-shu-yong-fa&quot;&gt;特殊用法&lt;a class=&quot;zola-anchor&quot; href=&quot;#te-shu-yong-fa&quot; aria-label=&quot;Anchor link for: te-shu-yong-fa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;wakarimasitade-te-shu-qing-kuang&quot;&gt;わかりました的特殊情况&lt;a class=&quot;zola-anchor&quot; href=&quot;#wakarimasitade-te-shu-qing-kuang&quot; aria-label=&quot;Anchor link for: wakarimasitade-te-shu-qing-kuang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;1-tu-ran-ming-bai&quot;&gt;1. 突然明白&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-tu-ran-ming-bai&quot; aria-label=&quot;Anchor link for: 1-tu-ran-ming-bai&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;あ、&lt;strong&gt;わかりました&lt;&#x2F;strong&gt;！
（啊，明白了！→恍然大悟）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;2-jing-guo-si-kao-hou-li-jie&quot;&gt;2. 经过思考后理解&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-jing-guo-si-kao-hou-li-jie&quot; aria-label=&quot;Anchor link for: 2-jing-guo-si-kao-hou-li-jie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;考えてみて、&lt;strong&gt;わかりました&lt;&#x2F;strong&gt;。
（想了想，明白了）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;3-li-mao-de-que-ren&quot;&gt;3. 礼貌的确认&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-li-mao-de-que-ren&quot; aria-label=&quot;Anchor link for: 3-li-mao-de-que-ren&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;わかりました&lt;&#x2F;strong&gt;。やってみます。
（明白了。我试试看）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;wakarimasude-chang-yong-qing-kuang&quot;&gt;わかります的常用情况&lt;a class=&quot;zola-anchor&quot; href=&quot;#wakarimasude-chang-yong-qing-kuang&quot; aria-label=&quot;Anchor link for: wakarimasude-chang-yong-qing-kuang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;1-neng-li-xun-wen-de-hui-da&quot;&gt;1. 能力询问的回答&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-neng-li-xun-wen-de-hui-da&quot; aria-label=&quot;Anchor link for: 1-neng-li-xun-wen-de-hui-da&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;A: 中国語が&lt;strong&gt;わかりますか&lt;&#x2F;strong&gt;？&lt;&#x2F;li&gt;
&lt;li&gt;B: はい、少し&lt;strong&gt;わかります&lt;&#x2F;strong&gt;。
（会一点中文）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;2-li-jie-zhuang-tai-de-biao-da&quot;&gt;2. 理解状态的表达&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-li-jie-zhuang-tai-de-biao-da&quot; aria-label=&quot;Anchor link for: 2-li-jie-zhuang-tai-de-biao-da&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;この説明が&lt;strong&gt;わかります&lt;&#x2F;strong&gt;。
（能理解这个说明）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;3-yi-ban-xing-chen-shu&quot;&gt;3. 一般性陈述&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-yi-ban-xing-chen-shu&quot; aria-label=&quot;Anchor link for: 3-yi-ban-xing-chen-shu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;彼の気持ちが&lt;strong&gt;わかります&lt;&#x2F;strong&gt;。
（能理解他的心情）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;shi-ji-dui-hua-li-zi&quot;&gt;实际对话例子&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-ji-dui-hua-li-zi&quot; aria-label=&quot;Anchor link for: shi-ji-dui-hua-li-zi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;li-zi-1-ke-tang-chang-jing&quot;&gt;例子1：课堂场景&lt;a class=&quot;zola-anchor&quot; href=&quot;#li-zi-1-ke-tang-chang-jing&quot; aria-label=&quot;Anchor link for: li-zi-1-ke-tang-chang-jing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;先生&lt;&#x2F;strong&gt;：来週はテストです。&lt;&#x2F;li&gt;
&lt;li&gt;学生**：**わかりました。 ✅&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;先生&lt;&#x2F;strong&gt;：質問が&lt;strong&gt;わかりますか&lt;&#x2F;strong&gt;？&lt;&#x2F;li&gt;
&lt;li&gt;学生**：はい、**わかります。 ✅&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;li-zi-2-gong-zuo-chang-jing&quot;&gt;例子2：工作场景&lt;a class=&quot;zola-anchor&quot; href=&quot;#li-zi-2-gong-zuo-chang-jing&quot; aria-label=&quot;Anchor link for: li-zi-2-gong-zuo-chang-jing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;上司&lt;&#x2F;strong&gt;：この資料を明日までに。&lt;&#x2F;li&gt;
&lt;li&gt;部下**：**わかりました。 ✅&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;上司&lt;&#x2F;strong&gt;：やり方は&lt;strong&gt;わかりますか&lt;&#x2F;strong&gt;？&lt;&#x2F;li&gt;
&lt;li&gt;部下**：はい、**わかります。 ✅&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;fou-ding-xing-shi&quot;&gt;否定形式&lt;a class=&quot;zola-anchor&quot; href=&quot;#fou-ding-xing-shi&quot; aria-label=&quot;Anchor link for: fou-ding-xing-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;wakarimasen-xian-zai-fou-ding&quot;&gt;&lt;strong&gt;わかりません&lt;&#x2F;strong&gt;（现在否定）&lt;a class=&quot;zola-anchor&quot; href=&quot;#wakarimasen-xian-zai-fou-ding&quot; aria-label=&quot;Anchor link for: wakarimasen-xian-zai-fou-ding&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;日本語が&lt;strong&gt;わかりません&lt;&#x2F;strong&gt;。
（不懂日语）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;wakarimasendesita-guo-qu-fou-ding&quot;&gt;&lt;strong&gt;わかりませんでした&lt;&#x2F;strong&gt;（过去否定）&lt;a class=&quot;zola-anchor&quot; href=&quot;#wakarimasendesita-guo-qu-fou-ding&quot; aria-label=&quot;Anchor link for: wakarimasendesita-guo-qu-fou-ding&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;その時は&lt;strong&gt;わかりませんでした&lt;&#x2F;strong&gt;。
（那时候不明白）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;ji-yi-ji-qiao&quot;&gt;记忆技巧&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-yi-ji-qiao&quot; aria-label=&quot;Anchor link for: ji-yi-ji-qiao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;wakarimasita-1&quot;&gt;わかりました&lt;a class=&quot;zola-anchor&quot; href=&quot;#wakarimasita-1&quot; aria-label=&quot;Anchor link for: wakarimasita-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;过去时 = 刚刚明白&lt;&#x2F;li&gt;
&lt;li&gt;用于：&lt;strong&gt;回应&lt;&#x2F;strong&gt;、&lt;strong&gt;确认&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;场景：听完说明后&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;wakarimasu-1&quot;&gt;わかります&lt;a class=&quot;zola-anchor&quot; href=&quot;#wakarimasu-1&quot; aria-label=&quot;Anchor link for: wakarimasu-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;现在时 = 能够理解&lt;&#x2F;li&gt;
&lt;li&gt;用于：&lt;strong&gt;能力&lt;&#x2F;strong&gt;、&lt;strong&gt;状态&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;场景：表达理解能力&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;chang-jian-cuo-wu&quot;&gt;常见错误&lt;a class=&quot;zola-anchor&quot; href=&quot;#chang-jian-cuo-wu&quot; aria-label=&quot;Anchor link for: chang-jian-cuo-wu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;❌ 错误用法：
A: 明日10時に来て。
B: わかります。（应该用わかりました）&lt;&#x2F;p&gt;
&lt;p&gt;❌ 错误用法：
A: 英語ができますか？
B: わかりました。（应该用わかります）&lt;&#x2F;p&gt;
&lt;p&gt;✅ 正确用法：
A: 明日10時に来て。
B: わかりました。&lt;&#x2F;p&gt;
&lt;p&gt;A: 英語ができますか？&lt;br &#x2F;&gt;
B: はい、わかります。&lt;&#x2F;p&gt;
&lt;p&gt;记忆口诀：回应用过去（わかりました），能力用现在（わかります）！&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Work | 吐槽</title>
          <pubDate>Wed, 02 Jul 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-07-02-something-about-work/</link>
          <guid>https://inasa.dev/posts/25-07-02-something-about-work/</guid>
          <description xml:base="https://inasa.dev/posts/25-07-02-something-about-work/">&lt;p&gt;当某老板以甲方为结款为由，资金不足要裁两个员工的时候，我心里还有点儿不是滋味。但是4月份中旬往后半个月，一直都只有我一个人在交接资料，那时还只是有点儿怀疑，前端怎么不交接？&lt;&#x2F;p&gt;
&lt;p&gt;时隔两个月，七月二号这天，某老板又来找我解决技术问题。由于需要远程他的电脑解决，再通过种种细节发现，原来只是把我干掉了。前端还在某公司里干活。&lt;&#x2F;p&gt;
&lt;p&gt;真他妈搞笑，裁人都不敢直接裁。还得和前端两个人配合演出戏。&lt;&#x2F;p&gt;
&lt;p&gt;在某公司除了前端和硬件设施之外，后端，基础设施，出差调试都是我干。工资还没前端高，后端工资没前端工资高，连平均工资都不到，笑了。唯一的优点就是朝九晚六。在某公司没学到什么东西，还得我教他们。某些人权威崇拜，想当然。每周开个会还含沙射影，指桑骂槐，也不看看某些人自己写的代码是什么狗屁，水平又臭。整天装腔作势，夸夸其谈，还经常自我膨胀。&lt;&#x2F;p&gt;
&lt;p&gt;最后，一开始就真诚的人，最后会变得最不真诚。&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>PostgreSQL | DISTINCT ON解析</title>
          <pubDate>Sun, 22 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-06-22-pg-distincton/</link>
          <guid>https://inasa.dev/posts/25-06-22-pg-distincton/</guid>
          <description xml:base="https://inasa.dev/posts/25-06-22-pg-distincton/">&lt;h3 id=&quot;ji-ben-gai-nian&quot;&gt;基本概念&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-ben-gai-nian&quot; aria-label=&quot;Anchor link for: ji-ben-gai-nian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;DISTINCT ON 是PostgreSQL特有的&lt;strong&gt;去重功能&lt;&#x2F;strong&gt;，允许在保留每组中最早&#x2F;最晚&#x2F;特定记录时去重。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;yu-fa-jie-xi&quot;&gt;语法解析&lt;a class=&quot;zola-anchor&quot; href=&quot;#yu-fa-jie-xi&quot; aria-label=&quot;Anchor link for: yu-fa-jie-xi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT DISTINCT&lt;&#x2F;span&gt; ON (column1, column2, ...) 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    column1, 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    column2, 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    ...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; table
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;ORDER BY&lt;&#x2F;span&gt; column1, column2, ..., additional_sorting_column;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;xiang-xi-shi-li-he-jie-shi&quot;&gt;详细示例和解释&lt;a class=&quot;zola-anchor&quot; href=&quot;#xiang-xi-shi-li-he-jie-shi&quot; aria-label=&quot;Anchor link for: xiang-xi-shi-li-he-jie-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1-ji-chu-shi-li&quot;&gt;1. 基础示例&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-ji-chu-shi-li&quot; aria-label=&quot;Anchor link for: 1-ji-chu-shi-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 原始数据
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;player_id | event_date  | other_column
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt;--------|--------------|--------------
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;1&lt;&#x2F;span&gt;         | &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;2023&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;01&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;01&lt;&#x2F;span&gt;  | A
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;1&lt;&#x2F;span&gt;         | &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;2023&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;01&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;02&lt;&#x2F;span&gt;  | B
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;1&lt;&#x2F;span&gt;         | &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;2023&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;01&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;03&lt;&#x2F;span&gt;  | C
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;2&lt;&#x2F;span&gt;         | &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;2024&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;01&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;01&lt;&#x2F;span&gt;  | X
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;2&lt;&#x2F;span&gt;         | &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;2024&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;01&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;02&lt;&#x2F;span&gt;  | Y
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; DISTINCT ON 查询
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT DISTINCT&lt;&#x2F;span&gt; ON (player_id) 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    player_id, 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    event_date,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    other_column
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; activity
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;ORDER BY&lt;&#x2F;span&gt; player_id, event_date;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 结果
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;player_id | event_date  | other_column
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt;--------|--------------|--------------
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;1&lt;&#x2F;span&gt;         | &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;2023&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;01&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;01&lt;&#x2F;span&gt;  | A  
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;2&lt;&#x2F;span&gt;         | &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;2024&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;01&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;01&lt;&#x2F;span&gt;  | X
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;2-zhi-xing-liu-cheng-xiang-jie&quot;&gt;2. 执行流程详解&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-zhi-xing-liu-cheng-xiang-jie&quot; aria-label=&quot;Anchor link for: 2-zhi-xing-liu-cheng-xiang-jie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;bu-zou-fen-xi&quot;&gt;步骤分析&lt;a class=&quot;zola-anchor&quot; href=&quot;#bu-zou-fen-xi&quot; aria-label=&quot;Anchor link for: bu-zou-fen-xi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DISTINCT ON (player_id)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;按player_id分组&lt;&#x2F;li&gt;
&lt;li&gt;每组只保留&lt;strong&gt;一行&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ORDER BY player_id, event_date&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;先按player_id排序&lt;&#x2F;li&gt;
&lt;li&gt;再按event_date排序&lt;&#x2F;li&gt;
&lt;li&gt;决定每组保留的具体行&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;3-fu-za-shi-li&quot;&gt;3. 复杂示例&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-fu-za-shi-li&quot; aria-label=&quot;Anchor link for: 3-fu-za-shi-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 查找每个玩家最早的登录记录
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT DISTINCT&lt;&#x2F;span&gt; ON (player_id) 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    player_id, 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    event_date &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; first_login,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    server_id,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    login_ip
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; activity
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;ORDER BY&lt;&#x2F;span&gt; player_id, event_date &lt;span class=&quot;z-keyword z-other z-order z-sql&quot;&gt;ASC&lt;&#x2F;span&gt;, server_id;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;4-bian-ti-yong-fa&quot;&gt;4. 变体用法&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-bian-ti-yong-fa&quot; aria-label=&quot;Anchor link for: 4-bian-ti-yong-fa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;a-duo-lie-distinct-on&quot;&gt;a. 多列DISTINCT ON&lt;a class=&quot;zola-anchor&quot; href=&quot;#a-duo-lie-distinct-on&quot; aria-label=&quot;Anchor link for: a-duo-lie-distinct-on&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 按国家和城市去重
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT DISTINCT&lt;&#x2F;span&gt; ON (country, city)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    country, 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    city, 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    population
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; cities
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;ORDER BY&lt;&#x2F;span&gt; country, city, population &lt;span class=&quot;z-keyword z-other z-order z-sql&quot;&gt;DESC&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;b-huo-qu-mei-zu-zui-da-zhi&quot;&gt;b. 获取每组最大值&lt;a class=&quot;zola-anchor&quot; href=&quot;#b-huo-qu-mei-zu-zui-da-zhi&quot; aria-label=&quot;Anchor link for: b-huo-qu-mei-zu-zui-da-zhi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 获取每个类别最高分数的记录
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT DISTINCT&lt;&#x2F;span&gt; ON (category)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    category,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    product_name,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    price
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; products
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;ORDER BY&lt;&#x2F;span&gt; category, price &lt;span class=&quot;z-keyword z-other z-order z-sql&quot;&gt;DESC&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;xing-neng-he-shi-xian&quot;&gt;性能和实现&lt;a class=&quot;zola-anchor&quot; href=&quot;#xing-neng-he-shi-xian&quot; aria-label=&quot;Anchor link for: xing-neng-he-shi-xian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;nei-bu-zhi-xing-ji-zhi&quot;&gt;内部执行机制&lt;a class=&quot;zola-anchor&quot; href=&quot;#nei-bu-zhi-xing-ji-zhi&quot; aria-label=&quot;Anchor link for: nei-bu-zhi-xing-ji-zhi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;1. 排序 (ORDER BY)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;2. 去重 (DISTINCT ON)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;3. 选择每组第一行
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;xing-neng-dui-bi&quot;&gt;性能对比&lt;a class=&quot;zola-anchor&quot; href=&quot;#xing-neng-dui-bi&quot; aria-label=&quot;Anchor link for: xing-neng-dui-bi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 方法1: DISTINCT ON (PostgreSQL)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT DISTINCT&lt;&#x2F;span&gt; ON (player_id) 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    player_id, 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    event_date
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; activity
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;ORDER BY&lt;&#x2F;span&gt; player_id, event_date;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 方法2: 子查询 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT&lt;&#x2F;span&gt; player_id, &lt;span class=&quot;z-support z-function z-aggregate z-sql&quot;&gt;MIN&lt;&#x2F;span&gt;(event_date) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; event_date
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; activity
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;GROUP BY&lt;&#x2F;span&gt; player_id;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 方法3: 窗口函数
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT&lt;&#x2F;span&gt; player_id, event_date
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; (
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;        player_id, 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;        event_date,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;        ROW_NUMBER&lt;span class=&quot;z-meta z-block z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-begin z-sql&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-scope z-end z-sql&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; OVER (
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            PARTITION BY player_id 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;            &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;ORDER BY&lt;&#x2F;span&gt; event_date
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;        ) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; rn
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; activity
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;) ranked
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;WHERE&lt;&#x2F;span&gt; rn &lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;1&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;xing-neng-you-hua&quot;&gt;性能优化&lt;a class=&quot;zola-anchor&quot; href=&quot;#xing-neng-you-hua&quot; aria-label=&quot;Anchor link for: xing-neng-you-hua&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 创建复合索引
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-create z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;CREATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;INDEX&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-sql&quot;&gt;idx_player_date&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;ON activity(player_id, event_date);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;gao-ji-yong-fa&quot;&gt;高级用法&lt;a class=&quot;zola-anchor&quot; href=&quot;#gao-ji-yong-fa&quot; aria-label=&quot;Anchor link for: gao-ji-yong-fa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1-fu-za-tiao-jian-xuan-ze&quot;&gt;1. 复杂条件选择&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-fu-za-tiao-jian-xuan-ze&quot; aria-label=&quot;Anchor link for: 1-fu-za-tiao-jian-xuan-ze&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 选择每个玩家最早的高分登录记录
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT DISTINCT&lt;&#x2F;span&gt; ON (player_id)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    player_id,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    event_date,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    score
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; activity
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;WHERE&lt;&#x2F;span&gt; score &lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;100&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;ORDER BY&lt;&#x2F;span&gt; player_id, event_date, score &lt;span class=&quot;z-keyword z-other z-order z-sql&quot;&gt;DESC&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;2-duo-wei-du-qu-zhong&quot;&gt;2. 多维度去重&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-duo-wei-du-qu-zhong&quot; aria-label=&quot;Anchor link for: 2-duo-wei-du-qu-zhong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 按年份和月份去重
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT DISTINCT&lt;&#x2F;span&gt; ON (
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    EXTRACT(YEAR &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; event_date), 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    EXTRACT(MONTH &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; event_date)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    EXTRACT(YEAR &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; event_date) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; year,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    EXTRACT(MONTH &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; event_date) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; month,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    &lt;span class=&quot;z-support z-function z-aggregate z-sql&quot;&gt;AVG&lt;&#x2F;span&gt;(score) &lt;span class=&quot;z-keyword z-operator z-assignment z-alias z-sql&quot;&gt;AS&lt;&#x2F;span&gt; avg_score
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; activity
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;ORDER BY&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    EXTRACT(YEAR &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; event_date), 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    EXTRACT(MONTH &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; event_date),
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    &lt;span class=&quot;z-support z-function z-aggregate z-sql&quot;&gt;AVG&lt;&#x2F;span&gt;(score) &lt;span class=&quot;z-keyword z-other z-order z-sql&quot;&gt;DESC&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;chang-jian-shi-yong-chang-jing&quot;&gt;常见使用场景&lt;a class=&quot;zola-anchor&quot; href=&quot;#chang-jian-shi-yong-chang-jing&quot; aria-label=&quot;Anchor link for: chang-jian-shi-yong-chang-jing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1-shu-ju-qu-zhong&quot;&gt;1. 数据去重&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-shu-ju-qu-zhong&quot; aria-label=&quot;Anchor link for: 1-shu-ju-qu-zhong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 保留最新的用户信息
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT DISTINCT&lt;&#x2F;span&gt; ON (email)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    email,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    name,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    last_login
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; users
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;ORDER BY&lt;&#x2F;span&gt; email, last_login &lt;span class=&quot;z-keyword z-other z-order z-sql&quot;&gt;DESC&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;2-shi-jian-xu-lie-fen-xi&quot;&gt;2. 时间序列分析&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-shi-jian-xu-lie-fen-xi&quot; aria-label=&quot;Anchor link for: 2-shi-jian-xu-lie-fen-xi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 每个产品最后一次销售
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT DISTINCT&lt;&#x2F;span&gt; ON (product_id)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    product_id,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    sale_date,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    total_amount
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; sales
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;ORDER BY&lt;&#x2F;span&gt; product_id, sale_date &lt;span class=&quot;z-keyword z-other z-order z-sql&quot;&gt;DESC&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;3-ri-zhi-fen-xi&quot;&gt;3. 日志分析&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-ri-zhi-fen-xi&quot; aria-label=&quot;Anchor link for: 3-ri-zhi-fen-xi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt; 每个IP最后一次访问
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT DISTINCT&lt;&#x2F;span&gt; ON (client_ip)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    client_ip,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    request_time,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    request_path
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; access_logs
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;ORDER BY&lt;&#x2F;span&gt; client_ip, request_time &lt;span class=&quot;z-keyword z-other z-order z-sql&quot;&gt;DESC&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;zhu-yi-shi-xiang&quot;&gt;注意事项&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhu-yi-shi-xiang&quot; aria-label=&quot;Anchor link for: zhu-yi-shi-xiang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;you-dian&quot;&gt;优点&lt;a class=&quot;zola-anchor&quot; href=&quot;#you-dian&quot; aria-label=&quot;Anchor link for: you-dian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;简洁明了&lt;&#x2F;li&gt;
&lt;li&gt;性能高效&lt;&#x2F;li&gt;
&lt;li&gt;PostgreSQL特有功能&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;ju-xian-xing&quot;&gt;局限性&lt;a class=&quot;zola-anchor&quot; href=&quot;#ju-xian-xing&quot; aria-label=&quot;Anchor link for: ju-xian-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;仅PostgreSQL支持&lt;&#x2F;li&gt;
&lt;li&gt;需要明确的排序规则&lt;&#x2F;li&gt;
&lt;li&gt;复杂场景可能需要子查询&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;zui-jia-shi-jian&quot;&gt;最佳实践&lt;a class=&quot;zola-anchor&quot; href=&quot;#zui-jia-shi-jian&quot; aria-label=&quot;Anchor link for: zui-jia-shi-jian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;明确排序列&lt;&#x2F;li&gt;
&lt;li&gt;考虑性能&lt;&#x2F;li&gt;
&lt;li&gt;创建合适索引&lt;&#x2F;li&gt;
&lt;li&gt;理解选择逻辑&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;tui-jian-chang-jing&quot;&gt;推荐场景&lt;a class=&quot;zola-anchor&quot; href=&quot;#tui-jian-chang-jing&quot; aria-label=&quot;Anchor link for: tui-jian-chang-jing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;去重&lt;&#x2F;li&gt;
&lt;li&gt;获取最新&#x2F;最早记录&lt;&#x2F;li&gt;
&lt;li&gt;简单的分组选择&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;DISTINCT ON 是PostgreSQL中非常强大且灵活的去重工具，理解其工作原理可以显著简化查询逻辑。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;Claude Sonnet 4&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | 为什么数据库应绕过Linux页面缓存</title>
          <pubDate>Fri, 20 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-06-20-why-databases-should-bypass-the-linux-page-cache/</link>
          <guid>https://inasa.dev/posts/25-06-20-why-databases-should-bypass-the-linux-page-cache/</guid>
          <description xml:base="https://inasa.dev/posts/25-06-20-why-databases-should-bypass-the-linux-page-cache/">&lt;p&gt;来看一下为什么 ScyllaDB 在读取时会完全绕过 Linux 缓存，并使用其自身高效的基于行的集成内部缓存。&lt;&#x2F;p&gt;
&lt;p&gt;Linux 页缓存（也称为磁盘缓存）是一种通用类型的缓存。尽管它可以进行调优以更好地服务于数据库类的工作负载，但从根本上讲它并不适合数据库的实现。&lt;&#x2F;p&gt;
&lt;p&gt;页缓存无法针对数据库所需的关键需求提供上下文，这对于实现最佳性能和控制是必须的。考虑到页缓存对内存的使用效率低下、负向缓存效果差、冗余的缓冲区、高昂的读操作 CPU 开销以及缓存过早淘汰（以及其他一些挑战），对于以性能为导向的数据库来说，采用不同的方法是合理的。&lt;&#x2F;p&gt;
&lt;p&gt;让我们来看一下 ScyllaDB（一款面向低延迟应用的数据库）是如何在读取时完全绕过 Linux 缓存，并使用其自身高效的基于行的集成内部缓存的。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;linuxye-mian-huan-cun-de-wen-ti&quot;&gt;Linux页面缓存的问题&lt;a class=&quot;zola-anchor&quot; href=&quot;#linuxye-mian-huan-cun-de-wen-ti&quot; aria-label=&quot;Anchor link for: linuxye-mian-huan-cun-de-wen-ti&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Linux 缓存在数据库实现方面效率低下，原因有以下几点。&lt;&#x2F;p&gt;
&lt;p&gt;Linux 页缓存通过将文件的页面大小分块存储在内存中，以减少昂贵的磁盘读取，从而提升操作系统性能。Linux 内核默认将文件视为 4KB 大小的分块。这确实能加快性能，但前提是数据量达到 4KB 或更大。问题在于，许多常见的数据库操作所涉及的数据量往往小于 4KB。在这些场景下，Linux 的 4KB 最小分块导致了较高的读取放大。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;读取放大（Read Amplification）是数据库与存储系统中的一个常用术语，意思是：为了获得一小部分所需的数据，系统实际上不得不读取远多于实际需要的数据。&lt;&#x2F;p&gt;
&lt;p&gt;假设你只需要 100 字节，而存储系统每次最小只能按 4096 字节读取，那么实际上就发生了读放大：你为获取少量数据“被迫”读取很多无用的数据。&lt;&#x2F;p&gt;
&lt;p&gt;读放大的本质是因为存储系统的最小读取单元（比如数据库页、操作系统页、SSD页）大于你的实际业务数据单元。&lt;&#x2F;p&gt;
&lt;p&gt;读放大的带来问题&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;浪费带宽和IO资源。&lt;&#x2F;li&gt;
&lt;li&gt;增加内存压力，可能把不相关数据装进缓存。&lt;&#x2F;li&gt;
&lt;li&gt;降低查询效率，尤其在高并发&#x2F;大量小请求场景下格外明显。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;举例&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;MySQL&#x2F;InnoDB：一行几百字节，底层按16KB页读；&lt;&#x2F;li&gt;
&lt;li&gt;Linux页缓存：只想访问一小行，但一次最少4KB；&lt;&#x2F;li&gt;
&lt;li&gt;SSD：每次读出一整个页面（比如4KB），但只用了几十字节。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;更糟糕的是，这些额外读取到内存的数据通常对后续查询没有用（因为其“空间局部性”很差）。在大多数情况下，这只是带宽的浪费。Cassandra 试图通过增加键缓存和行缓存来缓解读放大问题，这两种缓存能直接存储经常被访问的对象。然而，Cassandra 的额外缓存带来了更高的整体复杂性，而且很难配置得当。运维人员需要为每个缓存分配内存，不同的分配比例会产生不同的性能特性，不同的工作负载又适合不同的设置。此外，运维人员还必须决定为 JVM 堆内存以及堆外内存结构分配多少内存。由于所有内存分配都是在启动时完成的，因此几乎不可能一次性配置得完全合理，特别是对于工作负载随时间动态变化的场景来说更是如此。&lt;&#x2F;p&gt;
&lt;p&gt;另一个问题：在底层实现中，Linux 页缓存还会执行同步阻塞操作，从而影响系统性能和可预测性。由于 Cassandra 并不知道所请求的对象是否存在于 Linux 页缓存中，所以对不在缓存中的页面的访问会导致页面错误和上下文切换，从磁盘读取数据。接着系统会再次进行上下文切换以运行另一个线程，原始线程会被暂停。最终，在磁盘数据就绪后（又一次中断上下文切换），内核才会把调度切回到最初的线程。&lt;&#x2F;p&gt;
&lt;p&gt;下图展示了 Cassandra 缓存体系结构，包括分层的键缓存、行缓存和底层的 Linux 页缓存。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;cdn.thenewstack.io&#x2F;media&#x2F;2024&#x2F;03&#x2F;045ffed7-image1a.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wo-men-de-mu-biao-geng-hao-de-xing-neng-he-kong-zhi&quot;&gt;我们的目标：更好的性能（和控制）&lt;a class=&quot;zola-anchor&quot; href=&quot;#wo-men-de-mu-biao-geng-hao-de-xing-neng-he-kong-zhi&quot; aria-label=&quot;Anchor link for: wo-men-de-mu-biao-geng-hao-de-xing-neng-he-kong-zhi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ScyllaDB 是一个高性能数据库，专注于提供超低延迟，即使在每秒操作量超过百万的负载下也能如此。由于 ScyllaDB 设计时就完全兼容 Apache Cassandra（后续又扩展了对 DynamoDB 的兼容性），它充分借鉴了 Cassandra 设计中的最佳元素。不过，Cassandra 对默认 Linux 页缓存的依赖并不在其内。&lt;&#x2F;p&gt;
&lt;p&gt;我们意识到，专用缓存比 Linux 的默认缓存可以带来更好的性能，因此我们实现了自己的缓存。我们的统一缓存能够根据任何类型的负载动态调整自身，免去了像 Apache Cassandra 那样需要手动调优多个不同缓存的麻烦。由于我们能清楚地知道哪些对象被缓存，因此可以精细控制缓存项目的加载和驱逐。此外，缓存还能根据不同的负载以及内存压力动态扩展或收缩。&lt;&#x2F;p&gt;
&lt;p&gt;当进行读取时，如果数据已经不在缓存中，ScyllaDB 会启动一个继续任务来异步地从磁盘读取数据。ScyllaDB 基于的 Seastar 框架会在微秒级（每核每秒可执行100万任务）内执行这个继续任务，并立即运行下一个任务。整个过程没有阻塞、没有繁重的上下文切换，也不会造成资源浪费。&lt;&#x2F;p&gt;
&lt;p&gt;这种缓存设计使每个 ScyllaDB 节点能够服务更多数据，从而用户可以用更少数量但更强大的节点和更大磁盘来组建更小的集群。同时，它还简化了运维工作，因为不再有多个相互竞争的缓存，并且能在运行时根据不同的工作负载动态调整缓存。此外，高效的内部缓存也让独立的外部缓存变得不再必要，从而带来了更高效、更可靠、更安全且更具性价比的统一解决方案。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;geng-shen-ru-scylladbhuan-cun-she-ji&quot;&gt;更深入Scylladb缓存设计&lt;a class=&quot;zola-anchor&quot; href=&quot;#geng-shen-ru-scylladbhuan-cun-she-ji&quot; aria-label=&quot;Anchor link for: geng-shen-ru-scylladbhuan-cun-she-ji&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;有了上述概述后，让我们更深入地了解 ScyllaDB 缓存实现的细节。首先，我们从副本端来看数据流。&lt;&#x2F;p&gt;
&lt;p&gt;当写入操作到达副本时，它首先会进入一个内存中的数据结构——memtable（内存表），它存储在内存中。为了使写入被认为是成功的，还必须将数据写入 commitlog（提交日志）以便恢复，但这里 commitlog 本身并不是重点。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;cdn.thenewstack.io&#x2F;media&#x2F;2024&#x2F;03&#x2F;a665b0c3-image2a.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;当 memtable（内存表）变得足够大时，我们会将其刷新到 SSTable（一种存储在磁盘上的不可变数据结构）中。此时会创建一个新的 memtable 来接收后续的写入，已刷写的 memtable 内容会与缓存进行合并，然后该 memtable 会从内存中移除。这个过程会不断循环，SSTable 也会不断积累。&lt;&#x2F;p&gt;
&lt;p&gt;当有读操作到来时，我们需要将 memtable 和所有累积的 SSTable 中的数据合并起来，以便获得所有已有写入的一个一致视图。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;cdn.thenewstack.io&#x2F;media&#x2F;2024&#x2F;03&#x2F;74e956f5-image3.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;在这里，实现读一致性相对比较简单。例如，可以通过对内存表（memtables）进行快照并将其固定在内存中，同时对 SSTable 进行快照，然后将所有来源的数据合并起来，从而实现一致性。不过，这里有一个问题：速度很慢。每次都要访问磁盘，还要从多个部分读取数据。而缓存则可以加快这个过程。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;cdn.thenewstack.io&#x2F;media&#x2F;2024&#x2F;03&#x2F;bf6d9981-image4.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;为了避免每次读取都访问磁盘，我们需要一个读通缓存（read-through cache），它在语义上能够代表磁盘上的所有内容（即 SSTable），并在内存中缓存其中的一部分数据。传统的实现方式是使用缓冲区缓存，将从 SSTable 文件读取的数据缓存在缓冲区中。这些缓冲区通常为 4 KB，这也是使用 Linux 页缓存时会得到的大小。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;wei-shen-me-bu-shi-yong-buffer-cache&quot;&gt;为什么不使用 Buffer Cache?&lt;a class=&quot;zola-anchor&quot; href=&quot;#wei-shen-me-bu-shi-yong-buffer-cache&quot; aria-label=&quot;Anchor link for: wei-shen-me-bu-shi-yong-buffer-cache&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;如前所述，这种方法存在一些问题，这就是为什么Scylladb不使用它的原因。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;nei-cun-li-yong-lu-di-xia&quot;&gt;内存利用率低下&lt;a class=&quot;zola-anchor&quot; href=&quot;#nei-cun-li-yong-lu-di-xia&quot; aria-label=&quot;Anchor link for: nei-cun-li-yong-lu-di-xia&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;如果你只想缓存一行数据，你需要缓存一个完整的缓冲区。一个缓冲区为4KB，但一行数据可能要小得多（比如只有300字节）。如果你的数据集大于可用内存，访问的局部性就不会很高，这就导致了内存的低效使用。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;fu-huan-cun-xiao-guo-bu-jia&quot;&gt;负缓存效果不佳&lt;a class=&quot;zola-anchor&quot; href=&quot;#fu-huan-cun-xiao-guo-bu-jia&quot; aria-label=&quot;Anchor link for: fu-huan-cun-xiao-guo-bu-jia&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;这种方法在实现负缓存时表现也很差。由于你没有具体的键，你需要缓存整个数据缓冲区来表示数据不存在。这进一步削弱了内存效率。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;you-yu-lsm-ri-zhi-jie-gou-he-bing-shu-dao-zhi-de-rong-yu-huan-chong-qu&quot;&gt;由于 LSM（日志结构合并树）导致的冗余缓冲区&lt;a class=&quot;zola-anchor&quot; href=&quot;#you-yu-lsm-ri-zhi-jie-gou-he-bing-shu-dao-zhi-de-rong-yu-huan-chong-qu&quot; aria-label=&quot;Anchor link for: you-yu-lsm-ri-zhi-jie-gou-he-bing-shu-dao-zhi-de-rong-yu-huan-chong-qu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;这种方法还存在更多问题：因为读取操作可能需要访问多个 SSTable，缓存某一行可能需要缓存多个缓冲区。这再次导致内存使用低效，同时还增加了 CPU 的开销。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;du-cao-zuo-de-gao-cpukai-xiao&quot;&gt;读操作的高CPU开销&lt;a class=&quot;zola-anchor&quot; href=&quot;#du-cao-zuo-de-gao-cpukai-xiao&quot; aria-label=&quot;Anchor link for: du-cao-zuo-de-gao-cpukai-xiao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;当某一行被缓存到多个缓冲区时，每次读取都必须将这些缓冲区中的数据进行合并，这会消耗CPU周期。除了CPU开销外，存储缓冲区还要求我们解析这些缓冲区。SSTable格式并不是为读取速度优化的，而是为紧凑存储优化。你需要顺序解析索引缓冲区以理解索引，然后再去解析数据文件。这会消耗更多的CPU资源。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;yin-sstableya-suo-dao-zhi-huan-cun-bei-guo-zao-qu-zhu&quot;&gt;因SSTable压缩导致缓存被过早驱逐&lt;a class=&quot;zola-anchor&quot; href=&quot;#yin-sstableya-suo-dao-zhi-huan-cun-bei-guo-zao-qu-zhu&quot; aria-label=&quot;Anchor link for: yin-sstableya-suo-dao-zhi-huan-cun-bei-guo-zao-qu-zhu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;SSTable压缩会重新写入SSTable，因为可能存在冗余或过期数据，这可能导致缓存被过早驱逐。压缩过程会写入一个新的SSTable，并删除旧的文件。删除旧文件意味着相关的缓冲区必须失效，这实际上也会使缓存失效。这样一来，读取性能会因此受到影响，因为缓存会出现未命中。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;shi-yong-dui-xiang-huan-cun-zuo-wei-ti-dai&quot;&gt;使用对象缓存作为替代&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-yong-dui-xiang-huan-cun-zuo-wei-ti-dai&quot; aria-label=&quot;Anchor link for: shi-yong-dui-xiang-huan-cun-zuo-wei-ti-dai&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;很明显，在这种情况下，缓冲区缓存方法存在许多问题。因此，我们选择了另一种方法：实现对象缓存。这种专用的缓存存储实际的行对象，比如 memtable 中的行对象，而不是与磁盘上的文件关联。你可以把它看作是另一个用来保存行数据的树结构。&lt;&#x2F;p&gt;
&lt;p&gt;这种数据结构没有我上面提到的那些问题。更具体地说，它针对快速读取和低 CPU 开销进行了优化。每一行只有一个版本，结合所有相关的 SSTable 数据。并且缓存是以行粒度完成的：如果你愿意，甚至可以只在缓存中保留一行数据。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;nei-cun-guan-li&quot;&gt;内存管理&lt;a class=&quot;zola-anchor&quot; href=&quot;#nei-cun-guan-li&quot; aria-label=&quot;Anchor link for: nei-cun-guan-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;我们完全不使用 Linux 的页缓存。我们将每个节点绝大部分可用内存都保留给 ScyllaDB，只为操作系统（比如用于套接字缓冲区）预留极小的一部分。ScyllaDB 所分配的内存主要用于缓存。缓存被分配为使用所有可用内存，并且在系统其他部分（比如 memtable 或运维任务）有压力时，会按需收缩。我们还实现了控制器，确保其他压力源不会从缓存中抢走太多内存。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;cpu-fen-pian&quot;&gt;CPU 分片&lt;a class=&quot;zola-anchor&quot; href=&quot;#cpu-fen-pian&quot; aria-label=&quot;Anchor link for: cpu-fen-pian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;另一个重要的设计元素是分片。通过我们每核一分片（shard-per-core）的架构，ScyllaDB 中的每个 CPU 都负责管理一部分数据，并且每个 CPU 都有独立的数据结构来进行管理。因此，每个 CPU 都有独立的缓存和独立的 memtable，并且这些数据结构只能由拥有它们的 CPU 访问。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;cdn.thenewstack.io&#x2F;media&#x2F;2024&#x2F;03&#x2F;73075c14-image5.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;每核单线程（Thread-per-core）是这一设计的另一个重要组成部分。所有处理都在每个 CPU 的单独线程中完成。执行被划分为短小的任务，这些任务按顺序运行，并采用协作式抢占，这意味着我们的代码能够精确地控制任务的边界。如果有抢占信号（通常来自定时器），那么任务就必须协作式地让出执行权。它不会在任意地方被抢占，而是可以确定可能的抢占点。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;huan-cun-yi-zhi-xing&quot;&gt;缓存一致性&lt;a class=&quot;zola-anchor&quot; href=&quot;#huan-cun-yi-zhi-xing&quot; aria-label=&quot;Anchor link for: huan-cun-yi-zhi-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;所有这些设计让我们能够在单个任务内对数据进行复杂操作，而无需处理真正的并发问题。如果我们采用多线程并从多个 CPU 访问数据，就会遇到这些问题。这意味着我们不需要使用锁，能够避免锁竞争，也无需实现复杂的无锁算法。我们的数据结构和算法因此可以很简单。例如，在读取时，可以在单个任务中同时访问缓存和 memtable，并且在二者上获得一致的视图。这是在没有任何同步机制参与的情况下实现的，这意味着一切都能高效运行，性能也非常可预测。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;fan-wei-cha-xun-he-fan-wei-shan-chu&quot;&gt;范围查询和范围删除&lt;a class=&quot;zola-anchor&quot; href=&quot;#fan-wei-cha-xun-he-fan-wei-shan-chu&quot; aria-label=&quot;Anchor link for: fan-wei-cha-xun-he-fan-wei-shan-chu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;支持我们的查询语言和数据模型，对于对象缓存来说可能是一个问题。ScyllaDB 不是一个简单的键值存储。我们支持更复杂的操作，如范围查询和范围删除，而这些操作会影响缓存的实现方式。这可能会导致对象缓存出现缓冲区缓存所没有的复杂情况。&lt;&#x2F;p&gt;
&lt;p&gt;例如，考虑范围查询。假设你有一个要扫描一组行的查询。如果你的缓存只是键值对缓存，你就无法利用缓存来加速读取，因为你永远无法知道缓存条目之间的数据是否也存储在磁盘上。结果就是，这种读取总是不得不去磁盘获取那些缺失的数据。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;cdn.thenewstack.io&#x2F;media&#x2F;2024&#x2F;03&#x2F;fb46f324-image6.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;我们的缓存专门设计用来处理这种情况。我们会存储有关范围连续性的信息，表明缓存中的某个范围是完整的（因此无需再去读取磁盘以确认是否还有更多条目）。如果你重新扫描，系统就不会再访问磁盘了。&lt;&#x2F;p&gt;
&lt;p&gt;此外，范围删除操作需要特殊处理。由于 ScyllaDB 的最终一致性模型，删除不仅仅是移除数据。它还会留下一个标记，以便将来进行数据校对。这个标记被称为“墓碑”（tombstone），而缓存则必须能够存储这个标记。我们的缓存对此已经做好了准备：它会利用前面提到的范围连续性机制——本质上就是在范围连续性信息中附加上墓碑标记。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;qi-ta-liang-ge-du-te-de-huan-cun-yao-su&quot;&gt;其他两个独特的缓存要素&lt;a class=&quot;zola-anchor&quot; href=&quot;#qi-ta-liang-ge-du-te-de-huan-cun-yao-su&quot; aria-label=&quot;Anchor link for: qi-ta-liang-ge-du-te-de-huan-cun-yao-su&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;在结束之前，让我们简要看看在 ScyllaDB 缓存中我们实现的另外两项有趣内容。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cache-bypass&quot;&gt;Cache Bypass&lt;a class=&quot;zola-anchor&quot; href=&quot;#cache-bypass&quot; aria-label=&quot;Anchor link for: cache-bypass&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;缓存绕过&lt;&#x2F;p&gt;
&lt;p&gt;ScyllaDB 属于读穿透型缓存，这意味着——默认情况下——你执行的每一次读取操作，都会将数据加入缓存，并随后为用户提供服务。然而，这并不总是用户所期望的。例如，如果你需要扫描大量数据，或者偶尔查询一些将来很可能不会再被读取的数据，这可能会导致缓存中重要的数据项被淘汰。&lt;&#x2F;p&gt;
&lt;p&gt;为防止这种情况，我们在 CQL 协议中扩展了 BYPASS CACHE 功能。这个扩展会告知数据库不要将本次查询过程中读取到的数据项加入缓存，从而避免重要记录被覆盖或淘汰。BYPASS CACHE 也经常与 ScyllaDB 的工作负载优先级（Workload Prioritization）功能配合使用，尤其适用于经常需要批量扫描数据的分析型业务场景。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sstable-index-caching&quot;&gt;SSTable Index Caching&lt;a class=&quot;zola-anchor&quot; href=&quot;#sstable-index-caching&quot; aria-label=&quot;Anchor link for: sstable-index-caching&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;我们还会缓存 SSTable 的索引组件，以进一步加快必须访问磁盘时的读取速度。SSTable 索引会在被访问时自动加入缓存；当内存压力较大时，索引会以不会影响缓存性能的方式被逐出。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.scylladb.com&#x2F;wp-content&#x2F;uploads&#x2F;cache6.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;SSTable 索引缓存的一个优势在于它对大分区性能的提升。下面，你可以看到我们在大分区直接从磁盘读取冷数据时的前后测量结果。请注意，在引入 SSTable 索引后，吞吐量提升了三倍以上，使得磁盘查找速度更快。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.scylladb.com&#x2F;wp-content&#x2F;uploads&#x2F;cache7.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;总的来说，ScyllaDB 拥有一个快速缓存系统，专门为提升读取速度进行优化。它非常高效，因为数据和缓存被部署在同一个 CPU 上。此外，它还能完整地支持查询语言和数据模型的语义，同时遵循 ScyllaDB 的一致性保证。&lt;&#x2F;p&gt;
&lt;p&gt;该缓存系统完全绕过了 Linux 内核缓存，从而支持低延迟读取，同时避免了外部缓存的复杂性。采用这种方法，使我们能够实现可控且可预测的低延迟（比如百万级 OPS 下 P99 延迟仅为个位数毫秒）。同时，这也让我们能够完全洞察诸如缓存命中与未命中、缓存逐出和缓存大小等细节，用户可以据此更好地理解并优化性能。我们的专用缓存系统通常可以将性能提升到足以让用户用它来替换外部缓存的程度。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;www.p99conf.io&#x2F;2025&#x2F;05&#x2F;22&#x2F;databases-linux-page-cache&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Japanese | 根据汉字选发音的小技巧</title>
          <pubDate>Sun, 08 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-06-08-japanese-pinyin-seion-dakuon-tricks/</link>
          <guid>https://inasa.dev/posts/25-06-08-japanese-pinyin-seion-dakuon-tricks/</guid>
          <description xml:base="https://inasa.dev/posts/25-06-08-japanese-pinyin-seion-dakuon-tricks/">&lt;ul&gt;
&lt;li&gt;除特殊单词外，应该适用于多数情况&lt;&#x2F;li&gt;
&lt;li&gt;考试时完全不知道读音的情况下&lt;&#x2F;li&gt;
&lt;li&gt;可以作为&quot;猜题&quot;的最后手段&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;zhong-wen-pin-yin-dui-ying-ri-yu-qing-zhuo-yin-dui-zhao-biao&quot;&gt;中文拼音对应日语清浊音对照表&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhong-wen-pin-yin-dui-ying-ri-yu-qing-zhuo-yin-dui-zhao-biao&quot; aria-label=&quot;Anchor link for: zhong-wen-pin-yin-dui-ying-ri-yu-qing-zhuo-yin-dui-zhao-biao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;中文拼音&lt;&#x2F;th&gt;&lt;th&gt;日语行&lt;&#x2F;th&gt;&lt;th&gt;例词&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&quot;d&quot;、&quot;t&quot;&lt;&#x2F;td&gt;&lt;td&gt;た（だ）行&lt;&#x2F;td&gt;&lt;td&gt;代替たいたい&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;l&quot;&lt;&#x2F;td&gt;&lt;td&gt;ら行&lt;&#x2F;td&gt;&lt;td&gt;来日らいにち&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;m&quot;&lt;&#x2F;td&gt;&lt;td&gt;ま行&lt;&#x2F;td&gt;&lt;td&gt;毎朝まいあさ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;n&quot;&lt;&#x2F;td&gt;&lt;td&gt;な行&lt;&#x2F;td&gt;&lt;td&gt;内容ないよう&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;z&quot;、&quot;c&quot;、&quot;s&quot;&lt;&#x2F;td&gt;&lt;td&gt;さ（ざ）行&lt;&#x2F;td&gt;&lt;td&gt;最高さいこう&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;b&quot;、&quot;p&quot;、&quot;f&quot;&lt;&#x2F;td&gt;&lt;td&gt;は（ば）行&lt;&#x2F;td&gt;&lt;td&gt;破壊はかい&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;g&quot;、&quot;h&quot;、&quot;k&quot;&lt;&#x2F;td&gt;&lt;td&gt;か（が）行&lt;&#x2F;td&gt;&lt;td&gt;会議かいぎ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;j&quot;、&quot;q&quot;、&quot;x&quot;&lt;&#x2F;td&gt;&lt;td&gt;か（が）行&lt;&#x2F;td&gt;&lt;td&gt;解決かいけつ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;zh&quot;、&quot;ch&quot;、&quot;sh&quot;&lt;&#x2F;td&gt;&lt;td&gt;さ（ざ）行 或た（だ）行&lt;&#x2F;td&gt;&lt;td&gt;実際じっさい&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
</description>
      </item>
      <item>
          <title>Japanese | 促音（っ）后面通常接的行</title>
          <pubDate>Sun, 08 Jun 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-06-08-japanese-seion-or-dakuon-after-sokuon/</link>
          <guid>https://inasa.dev/posts/25-06-08-japanese-seion-or-dakuon-after-sokuon/</guid>
          <description xml:base="https://inasa.dev/posts/25-06-08-japanese-seion-or-dakuon-after-sokuon/">&lt;p&gt;促音（っ）后面通常接以下行：&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zhu-yao-gui-lu&quot;&gt;主要规律：&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhu-yao-gui-lu&quot; aria-label=&quot;Anchor link for: zhu-yao-gui-lu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;1-kaxing-zui-chang-jian&quot;&gt;1. &lt;strong&gt;か行&lt;&#x2F;strong&gt;（最常见）&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-kaxing-zui-chang-jian&quot; aria-label=&quot;Anchor link for: 1-kaxing-zui-chang-jian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;がっこう（学校）&lt;&#x2F;li&gt;
&lt;li&gt;さっき（刚才）&lt;&#x2F;li&gt;
&lt;li&gt;やっぱり（果然）&lt;&#x2F;li&gt;
&lt;li&gt;ばっちり（完美）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;2-saxing&quot;&gt;2. &lt;strong&gt;さ行&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-saxing&quot; aria-label=&quot;Anchor link for: 2-saxing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;いっしょ（一緒）&lt;&#x2F;li&gt;
&lt;li&gt;ざっし（杂志）&lt;&#x2F;li&gt;
&lt;li&gt;やっと（终于）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;3-taxing&quot;&gt;3. &lt;strong&gt;た行&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-taxing&quot; aria-label=&quot;Anchor link for: 3-taxing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;もっと（更多）&lt;&#x2F;li&gt;
&lt;li&gt;きって（邮票）&lt;&#x2F;li&gt;
&lt;li&gt;しっている（知道）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;4-paxing-haxing-de-ban-zhuo-yin&quot;&gt;4. &lt;strong&gt;ぱ行&lt;&#x2F;strong&gt;（は行的半浊音）&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-paxing-haxing-de-ban-zhuo-yin&quot; aria-label=&quot;Anchor link for: 4-paxing-haxing-de-ban-zhuo-yin&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;いっぱい（很多）&lt;&#x2F;li&gt;
&lt;li&gt;ちょっぴり（一点点）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;ji-yi-yao-dian&quot;&gt;记忆要点：&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-yi-yao-dian&quot; aria-label=&quot;Anchor link for: ji-yi-yao-dian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;✅ &lt;strong&gt;促音主要出现在清音前&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;か、さ、た、ぱ行&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;❌ &lt;strong&gt;很少出现在以下音前&lt;&#x2F;strong&gt;：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;あ行（元音）&lt;&#x2F;li&gt;
&lt;li&gt;な行、ま行、や行、ら行、わ行&lt;&#x2F;li&gt;
&lt;li&gt;が行、ざ行、だ行、ば行（浊音）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;fa-yin-te-dian&quot;&gt;发音特点：&lt;a class=&quot;zola-anchor&quot; href=&quot;#fa-yin-te-dian&quot; aria-label=&quot;Anchor link for: fa-yin-te-dian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;促音是一个&lt;strong&gt;停顿&lt;&#x2F;strong&gt;，相当于憋住一拍，然后发出后面的音，所以后面通常是&lt;strong&gt;爆破音&lt;&#x2F;strong&gt;或&lt;strong&gt;摩擦音&lt;&#x2F;strong&gt;（清音）。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;记忆口诀&lt;&#x2F;strong&gt;：促音后面&quot;卡萨塔帕&quot;（かさ た ぱ）&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Japanese | 敬体形和简体形</title>
          <pubDate>Mon, 26 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-05-26-japanese-polite-plain-form/</link>
          <guid>https://inasa.dev/posts/25-05-26-japanese-polite-plain-form/</guid>
          <description xml:base="https://inasa.dev/posts/25-05-26-japanese-polite-plain-form/">&lt;h2 id=&quot;jing-ti-he-jian-ti&quot;&gt;敬体和简体&lt;a class=&quot;zola-anchor&quot; href=&quot;#jing-ti-he-jian-ti&quot; aria-label=&quot;Anchor link for: jing-ti-he-jian-ti&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;jing-ti&quot;&gt;敬体：&lt;a class=&quot;zola-anchor&quot; href=&quot;#jing-ti&quot; aria-label=&quot;Anchor link for: jing-ti&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;面对长辈、上级等比自己身份地位高的人，或与自己关系不是亲近的人时使用&lt;&#x2F;li&gt;
&lt;li&gt;谓语为&quot;〜です&quot;、&quot;〜ます&quot;（及其各种形式）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;jian-ti&quot;&gt;简体：&lt;a class=&quot;zola-anchor&quot; href=&quot;#jian-ti&quot; aria-label=&quot;Anchor link for: jian-ti&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;面对晚辈、下级或关系较密切的人时使用&lt;&#x2F;li&gt;
&lt;li&gt;不使用&quot;ます&quot;、&quot;です&quot;的形式&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;≠某个词类的活用形式  →句子的概念&#x2F;各种词类做谓语时的形式&lt;&#x2F;p&gt;
&lt;h3 id=&quot;jing-ti-xing-shi&quot;&gt;敬体形式：&lt;a class=&quot;zola-anchor&quot; href=&quot;#jing-ti-xing-shi&quot; aria-label=&quot;Anchor link for: jing-ti-xing-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&quot;ます&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&quot;ません&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&quot;ました&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&quot;ませんでした&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;jian-ti-xing-shi&quot;&gt;简体形式：&lt;a class=&quot;zola-anchor&quot; href=&quot;#jian-ti-xing-shi&quot; aria-label=&quot;Anchor link for: jian-ti-xing-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;动词基本形&lt;&#x2F;li&gt;
&lt;li&gt;た形&lt;&#x2F;li&gt;
&lt;li&gt;ない形&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;注：一类形容词&#x2F;二类形容词&#x2F;名词 并无敬体简体之分，变化其作谓语时，后接的&quot;です&quot;部分&lt;&#x2F;p&gt;
&lt;h2 id=&quot;dong-ci-de-jian-ti-xing-shi&quot;&gt;动词的简体形式&lt;a class=&quot;zola-anchor&quot; href=&quot;#dong-ci-de-jian-ti-xing-shi&quot; aria-label=&quot;Anchor link for: dong-ci-de-jian-ti-xing-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;dong-ci-bian-hua-dui-zhao-biao&quot;&gt;动词变化对照表&lt;a class=&quot;zola-anchor&quot; href=&quot;#dong-ci-bian-hua-dui-zhao-biao&quot; aria-label=&quot;Anchor link for: dong-ci-bian-hua-dui-zhao-biao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;时态&lt;&#x2F;th&gt;&lt;th&gt;&lt;&#x2F;th&gt;&lt;th&gt;敬体形&lt;&#x2F;th&gt;&lt;th&gt;简体形&lt;&#x2F;th&gt;&lt;th&gt;敬体形&lt;&#x2F;th&gt;&lt;th&gt;简体形&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;现在将来&lt;br&gt;形式&lt;&#x2F;td&gt;&lt;td&gt;肯定&lt;&#x2F;td&gt;&lt;td&gt;買います (买)&lt;&#x2F;td&gt;&lt;td&gt;買う (基本形)&lt;&#x2F;td&gt;&lt;td&gt;あります (有)&lt;&#x2F;td&gt;&lt;td&gt;ある&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;否定&lt;&#x2F;td&gt;&lt;td&gt;買いません&lt;&#x2F;td&gt;&lt;td&gt;買わない (ない形)&lt;&#x2F;td&gt;&lt;td&gt;ありません&lt;&#x2F;td&gt;&lt;td&gt;ない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;过去&lt;br&gt;形式&lt;&#x2F;td&gt;&lt;td&gt;肯定&lt;&#x2F;td&gt;&lt;td&gt;買いました&lt;&#x2F;td&gt;&lt;td&gt;買った (た形)&lt;&#x2F;td&gt;&lt;td&gt;ありました&lt;&#x2F;td&gt;&lt;td&gt;あった&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;否定&lt;&#x2F;td&gt;&lt;td&gt;買いませんでした&lt;&#x2F;td&gt;&lt;td&gt;買わなかった&lt;br&gt;(なかった形)&lt;&#x2F;td&gt;&lt;td&gt;ありませんでした&lt;&#x2F;td&gt;&lt;td&gt;なかった&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;注：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;敬体形都是以&quot;ます&quot;或其变化形式结尾&lt;&#x2F;li&gt;
&lt;li&gt;简体形包括动词的基本形、ない形和た形&lt;&#x2F;li&gt;
&lt;li&gt;时态分为现在将来形式和过去形式，每种时态都有肯定和否定两种&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;yi-lei-xing-rong-ci-wei-yu-xing-shi-de-jian-ti-xing&quot;&gt;一类形容词谓语形式的简体形&lt;a class=&quot;zola-anchor&quot; href=&quot;#yi-lei-xing-rong-ci-wei-yu-xing-shi-de-jian-ti-xing&quot; aria-label=&quot;Anchor link for: yi-lei-xing-rong-ci-wei-yu-xing-shi-de-jian-ti-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;yi-lei-xing-rong-ci-bian-hua-dui-zhao-biao-yi-mang-sii-wei-li&quot;&gt;一类形容词变化对照表（以「忙しい」为例）&lt;a class=&quot;zola-anchor&quot; href=&quot;#yi-lei-xing-rong-ci-bian-hua-dui-zhao-biao-yi-mang-sii-wei-li&quot; aria-label=&quot;Anchor link for: yi-lei-xing-rong-ci-bian-hua-dui-zhao-biao-yi-mang-sii-wei-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;时态&lt;&#x2F;th&gt;&lt;th&gt;&lt;&#x2F;th&gt;&lt;th&gt;敬体形&lt;&#x2F;th&gt;&lt;th&gt;简体形&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;现在将来&lt;br&gt;形式&lt;&#x2F;td&gt;&lt;td&gt;肯定&lt;&#x2F;td&gt;&lt;td&gt;忙しいです (忙)&lt;&#x2F;td&gt;&lt;td&gt;忙しい&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;否定&lt;&#x2F;td&gt;&lt;td&gt;忙しくないです&lt;br&gt;忙しくありません&lt;&#x2F;td&gt;&lt;td&gt;忙しくない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;过去&lt;br&gt;形式&lt;&#x2F;td&gt;&lt;td&gt;肯定&lt;&#x2F;td&gt;&lt;td&gt;忙しかったです&lt;&#x2F;td&gt;&lt;td&gt;忙しかった&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;否定&lt;&#x2F;td&gt;&lt;td&gt;忙しくなかったです&lt;br&gt;忙しくありませんでした&lt;&#x2F;td&gt;&lt;td&gt;忙しくなかった&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;说明：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;一类形容词的特征是以「い」结尾&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;简体形式：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;现在肯定：直接使用形容词原形（〜い）&lt;&#x2F;li&gt;
&lt;li&gt;现在否定：词尾「い」变为「くない」&lt;&#x2F;li&gt;
&lt;li&gt;过去肯定：词尾「い」变为「かった」&lt;&#x2F;li&gt;
&lt;li&gt;过去否定：词尾「い」变为「くなかった」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;敬体形式：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;就是在简体形后面加上「です」&lt;&#x2F;li&gt;
&lt;li&gt;否定形有两种表达方式：「〜くないです」和「〜くありません」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;er-lei-xing-rong-ci-wei-yu-xing-shi-de-jian-ti-xing&quot;&gt;二类形容词谓语形式的简体形&lt;a class=&quot;zola-anchor&quot; href=&quot;#er-lei-xing-rong-ci-wei-yu-xing-shi-de-jian-ti-xing&quot; aria-label=&quot;Anchor link for: er-lei-xing-rong-ci-wei-yu-xing-shi-de-jian-ti-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;使用「簡単」(简单)作为例子：&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;时态&lt;&#x2F;th&gt;&lt;th&gt;&lt;&#x2F;th&gt;&lt;th&gt;敬体形&lt;&#x2F;th&gt;&lt;th&gt;简体形&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;现在将来&lt;br&gt;形式&lt;&#x2F;td&gt;&lt;td&gt;肯定&lt;&#x2F;td&gt;&lt;td&gt;簡単です&lt;&#x2F;td&gt;&lt;td&gt;簡単だ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;否定&lt;&#x2F;td&gt;&lt;td&gt;簡単ではありません&lt;&#x2F;td&gt;&lt;td&gt;簡単ではない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;过去&lt;br&gt;形式&lt;&#x2F;td&gt;&lt;td&gt;肯定&lt;&#x2F;td&gt;&lt;td&gt;簡単でした&lt;&#x2F;td&gt;&lt;td&gt;簡単だった&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;否定&lt;&#x2F;td&gt;&lt;td&gt;簡単ではありませんでした&lt;&#x2F;td&gt;&lt;td&gt;簡単ではなかった&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;ming-ci-wei-yu-xing-shi-de-jian-ti-xing&quot;&gt;名词谓语形式的简体形&lt;a class=&quot;zola-anchor&quot; href=&quot;#ming-ci-wei-yu-xing-shi-de-jian-ti-xing&quot; aria-label=&quot;Anchor link for: ming-ci-wei-yu-xing-shi-de-jian-ti-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;使用「晴れ」(晴天)作为例子：&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;时态&lt;&#x2F;th&gt;&lt;th&gt;&lt;&#x2F;th&gt;&lt;th&gt;敬体形&lt;&#x2F;th&gt;&lt;th&gt;简体形&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;现在将来&lt;br&gt;形式&lt;&#x2F;td&gt;&lt;td&gt;肯定&lt;&#x2F;td&gt;&lt;td&gt;晴れです&lt;&#x2F;td&gt;&lt;td&gt;晴れだ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;否定&lt;&#x2F;td&gt;&lt;td&gt;晴れではありません&lt;&#x2F;td&gt;&lt;td&gt;晴れではない&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;过去&lt;br&gt;形式&lt;&#x2F;td&gt;&lt;td&gt;肯定&lt;&#x2F;td&gt;&lt;td&gt;晴れでした&lt;&#x2F;td&gt;&lt;td&gt;晴れだった&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;否定&lt;&#x2F;td&gt;&lt;td&gt;晴れではありませんでした&lt;&#x2F;td&gt;&lt;td&gt;晴れではなかった&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;主要变化规则：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;二类形容词和名词的变化规则基本相同&lt;&#x2F;li&gt;
&lt;li&gt;简体形：
&lt;ul&gt;
&lt;li&gt;现在肯定：词尾加「だ」&lt;&#x2F;li&gt;
&lt;li&gt;现在否定：「では（じゃ）ない」&lt;&#x2F;li&gt;
&lt;li&gt;过去肯定：「だった」&lt;&#x2F;li&gt;
&lt;li&gt;过去否定：「ではなかった」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;敬体形：
&lt;ul&gt;
&lt;li&gt;现在肯定：「です」&lt;&#x2F;li&gt;
&lt;li&gt;现在否定：「ではありません」&lt;&#x2F;li&gt;
&lt;li&gt;过去肯定：「でした」&lt;&#x2F;li&gt;
&lt;li&gt;过去否定：「ではありませんでした」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;jian-ti-yi-wen-ju-de-gou-cheng-gui-ze&quot;&gt;简体疑问句的构成规则&lt;a class=&quot;zola-anchor&quot; href=&quot;#jian-ti-yi-wen-ju-de-gou-cheng-gui-ze&quot; aria-label=&quot;Anchor link for: jian-ti-yi-wen-ju-de-gou-cheng-gui-ze&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;dong-ci-wei-yu-ju-de-bian-hua&quot;&gt;动词谓语句的变化：&lt;a class=&quot;zola-anchor&quot; href=&quot;#dong-ci-wei-yu-ju-de-bian-hua&quot; aria-label=&quot;Anchor link for: dong-ci-wei-yu-ju-de-bian-hua&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;将敬体形式改为简体形式&lt;&#x2F;li&gt;
&lt;li&gt;去掉表示疑问的「か」&lt;&#x2F;li&gt;
&lt;li&gt;口语时：句尾用升调&lt;&#x2F;li&gt;
&lt;li&gt;书面时：句末加「?」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;例句：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;コーヒー、飲む？ ← 飲みますか。
(要喝咖啡吗？)&lt;&#x2F;li&gt;
&lt;li&gt;昨日テレビ、見た？ ← 見ましたか。
(昨天看电视了吗？)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;xing-rong-ci-ming-ci-wei-yu-ju-de-bian-hua&quot;&gt;形容词、名词谓语句的变化：&lt;a class=&quot;zola-anchor&quot; href=&quot;#xing-rong-ci-ming-ci-wei-yu-ju-de-bian-hua&quot; aria-label=&quot;Anchor link for: xing-rong-ci-ming-ci-wei-yu-ju-de-bian-hua&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;去掉「ですか」&lt;&#x2F;li&gt;
&lt;li&gt;口语时：句尾用升调&lt;&#x2F;li&gt;
&lt;li&gt;书面时：句末加「?」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;例句：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;その カレー、おいしい？ ← おいしいですか。
(那个咖喱好吃吗？)&lt;&#x2F;li&gt;
&lt;li&gt;森さんの アパート、静か？ ← 静かですか。
(森先生的公寓安静吗？)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;总结：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;简体疑问句主要是通过去掉敬体的标志词（ます、です）和疑问助词「か」来形成&lt;&#x2F;li&gt;
&lt;li&gt;在口语中用升调来表示疑问语气&lt;&#x2F;li&gt;
&lt;li&gt;书面语中则通过添加问号来表示疑问&lt;&#x2F;li&gt;
&lt;li&gt;这种形式多用于朋友间的随意对话&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;jian-ti-yi-wen-ju-guo-qu-shi-tai-de-bu-tong-dian&quot;&gt;简体疑问句 - 过去时态的不同点&lt;a class=&quot;zola-anchor&quot; href=&quot;#jian-ti-yi-wen-ju-guo-qu-shi-tai-de-bu-tong-dian&quot; aria-label=&quot;Anchor link for: jian-ti-yi-wen-ju-guo-qu-shi-tai-de-bu-tong-dian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;bu-tong-dian-shuo-ming&quot;&gt;不同点说明：&lt;a class=&quot;zola-anchor&quot; href=&quot;#bu-tong-dian-shuo-ming&quot; aria-label=&quot;Anchor link for: bu-tong-dian-shuo-ming&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;过去时态的简体疑问句构成方式根据词类有所不同：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;一类形容词：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;去掉「でした」&lt;&#x2F;li&gt;
&lt;li&gt;句尾读升调&lt;&#x2F;li&gt;
&lt;li&gt;加问号&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;二类形容词&#x2F;名词：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;使用「だった」&lt;&#x2F;li&gt;
&lt;li&gt;句尾读升调&lt;&#x2F;li&gt;
&lt;li&gt;加问号&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;li-ju-jie-xi&quot;&gt;例句解析：&lt;a class=&quot;zola-anchor&quot; href=&quot;#li-ju-jie-xi&quot; aria-label=&quot;Anchor link for: li-ju-jie-xi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;昨日、スキー場は 雪だった？
← 雪でしたか。
(昨天滑雪场有雪吗？)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;名词「雪」的过去时疑问句&lt;&#x2F;li&gt;
&lt;li&gt;敬体形「でした」→ 简体形「だった」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;昨日の 試験は 難しかった？
← 昨日の 試験は 難しかったですか。
(昨天的考试难吗？)&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;一类形容词「難しい」的过去时疑问句&lt;&#x2F;li&gt;
&lt;li&gt;去掉「でした」，保留「難しかった」&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;注意点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;过去时态的简体疑问句形式比现在时态更复杂&lt;&#x2F;li&gt;
&lt;li&gt;需要注意区分一类形容词和二类形容词&#x2F;名词的不同变化方式&lt;&#x2F;li&gt;
&lt;li&gt;无论哪种形式，都需要用升调语气和问号来表示疑问语气&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;hui-da-jian-ti-yi-wen-ju-shi-de-yong-ci-bian-hua&quot;&gt;回答简体疑问句时的用词变化&lt;a class=&quot;zola-anchor&quot; href=&quot;#hui-da-jian-ti-yi-wen-ju-shi-de-yong-ci-bian-hua&quot; aria-label=&quot;Anchor link for: hui-da-jian-ti-yi-wen-ju-shi-de-yong-ci-bian-hua&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;当回答简体疑问句时，常用语的变化规则如下：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;肯定回答：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;はい → うん
(是的 → 嗯&#x2F;对)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;否定回答：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;いいえ → ううん
(不是 → 嗯-嗯&#x2F;不对)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;程度表达：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;あまり → あんまり
(不太&#x2F;不怎么 → 不太&#x2F;不怎么【口语形式】)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;说明：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;这些变化主要用于非正式场合，比如与朋友交谈时&lt;&#x2F;li&gt;
&lt;li&gt;是将较为正式的用语转换为更口语化的表达&lt;&#x2F;li&gt;
&lt;li&gt;うん 和 ううん 的语气比 はい 和 いいえ 更随意轻松&lt;&#x2F;li&gt;
&lt;li&gt;あんまり 是 あまり 的口语形式，意思相同&lt;&#x2F;li&gt;
&lt;li&gt;这种变化体现了日语中正式用语和随意用语的区分&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;使用场景：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;适用于与关系亲近的人交谈&lt;&#x2F;li&gt;
&lt;li&gt;在非正式场合&lt;&#x2F;li&gt;
&lt;li&gt;日常对话中&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Japanese | 动词的基本形</title>
          <pubDate>Mon, 26 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-05-26-japanese-verb-basic/</link>
          <guid>https://inasa.dev/posts/25-05-26-japanese-verb-basic/</guid>
          <description xml:base="https://inasa.dev/posts/25-05-26-japanese-verb-basic/">&lt;p&gt;&lt;strong&gt;动词基本形：又叫&quot;词典形（辞書形）原形&quot;&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;dong-1-wu-duan-dong-ci&quot;&gt;动1（五段动词）&lt;a class=&quot;zola-anchor&quot; href=&quot;#dong-1-wu-duan-dong-ci&quot; aria-label=&quot;Anchor link for: dong-1-wu-duan-dong-ci&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&quot;ます形&quot;去掉&quot;ます&quot;后的最后一个假名→相应的&quot;う段&quot;假名&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;書きます → 書き → 書く&lt;&#x2F;li&gt;
&lt;li&gt;急ぎます → 急ぎ → 急ぐ&lt;&#x2F;li&gt;
&lt;li&gt;買います → 買い → 買う&lt;&#x2F;li&gt;
&lt;li&gt;話します → 話し → 話す&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;dong-2-yi-duan-dong-ci&quot;&gt;动2（一段动词）&lt;a class=&quot;zola-anchor&quot; href=&quot;#dong-2-yi-duan-dong-ci&quot; aria-label=&quot;Anchor link for: dong-2-yi-duan-dong-ci&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;ます → る&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;食べます → 食べる&lt;&#x2F;li&gt;
&lt;li&gt;見ます → 見る&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;dong-3&quot;&gt;动3&lt;a class=&quot;zola-anchor&quot; href=&quot;#dong-3&quot; aria-label=&quot;Anchor link for: dong-3&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;sabian&quot;&gt;サ変&lt;a class=&quot;zola-anchor&quot; href=&quot;#sabian&quot; aria-label=&quot;Anchor link for: sabian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;します → する&lt;&#x2F;li&gt;
&lt;li&gt;勉強します → 勉強する&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;kabian&quot;&gt;カ変&lt;a class=&quot;zola-anchor&quot; href=&quot;#kabian&quot; aria-label=&quot;Anchor link for: kabian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;来ます → 来る（くる）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;类别&lt;&#x2F;th&gt;&lt;th&gt;ます形&lt;&#x2F;th&gt;&lt;th&gt;去掉ます&lt;&#x2F;th&gt;&lt;th&gt;基本形&lt;&#x2F;th&gt;&lt;th&gt;基本形&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;一类动词&lt;&#x2F;td&gt;&lt;td&gt;書きます&lt;&#x2F;td&gt;&lt;td&gt;かき&lt;&#x2F;td&gt;&lt;td&gt;書く&lt;&#x2F;td&gt;&lt;td&gt;かく&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;急ぎます&lt;&#x2F;td&gt;&lt;td&gt;いそぎ&lt;&#x2F;td&gt;&lt;td&gt;急ぐ&lt;&#x2F;td&gt;&lt;td&gt;いそぐ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;飛びます&lt;&#x2F;td&gt;&lt;td&gt;とび&lt;&#x2F;td&gt;&lt;td&gt;飛ぶ&lt;&#x2F;td&gt;&lt;td&gt;とぶ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;読みます&lt;&#x2F;td&gt;&lt;td&gt;よみ&lt;&#x2F;td&gt;&lt;td&gt;読む&lt;&#x2F;td&gt;&lt;td&gt;よむ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;死にます&lt;&#x2F;td&gt;&lt;td&gt;しに&lt;&#x2F;td&gt;&lt;td&gt;死ぬ&lt;&#x2F;td&gt;&lt;td&gt;しぬ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;待ちます&lt;&#x2F;td&gt;&lt;td&gt;まち&lt;&#x2F;td&gt;&lt;td&gt;待つ&lt;&#x2F;td&gt;&lt;td&gt;まつ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;売ります&lt;&#x2F;td&gt;&lt;td&gt;うり&lt;&#x2F;td&gt;&lt;td&gt;売る&lt;&#x2F;td&gt;&lt;td&gt;うる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;買います&lt;&#x2F;td&gt;&lt;td&gt;かい&lt;&#x2F;td&gt;&lt;td&gt;買う&lt;&#x2F;td&gt;&lt;td&gt;かう&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;話します&lt;&#x2F;td&gt;&lt;td&gt;はなし&lt;&#x2F;td&gt;&lt;td&gt;話す&lt;&#x2F;td&gt;&lt;td&gt;はなす&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;二类动词&lt;&#x2F;td&gt;&lt;td&gt;食べます&lt;&#x2F;td&gt;&lt;td&gt;たべ&lt;&#x2F;td&gt;&lt;td&gt;食べる&lt;&#x2F;td&gt;&lt;td&gt;たべる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;見ます&lt;&#x2F;td&gt;&lt;td&gt;み&lt;&#x2F;td&gt;&lt;td&gt;見る&lt;&#x2F;td&gt;&lt;td&gt;みる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;三类动词&lt;&#x2F;td&gt;&lt;td&gt;来ます&lt;&#x2F;td&gt;&lt;td&gt;き&lt;&#x2F;td&gt;&lt;td&gt;来る&lt;&#x2F;td&gt;&lt;td&gt;くる&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;します&lt;&#x2F;td&gt;&lt;td&gt;し&lt;&#x2F;td&gt;&lt;td&gt;する&lt;&#x2F;td&gt;&lt;td&gt;する&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
</description>
      </item>
      <item>
          <title>Japanese | 动词的「ない」形</title>
          <pubDate>Mon, 26 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-05-26-japanese-verb-nai/</link>
          <guid>https://inasa.dev/posts/25-05-26-japanese-verb-nai/</guid>
          <description xml:base="https://inasa.dev/posts/25-05-26-japanese-verb-nai/">&lt;h2 id=&quot;yong-fa-yi-ban-yong-yu-biao-shi-fou-ding&quot;&gt;用法：一般用于表示否定。&lt;a class=&quot;zola-anchor&quot; href=&quot;#yong-fa-yi-ban-yong-yu-biao-shi-fou-ding&quot; aria-label=&quot;Anchor link for: yong-fa-yi-ban-yong-yu-biao-shi-fou-ding&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h2 id=&quot;huo-yong&quot;&gt;活用：&lt;a class=&quot;zola-anchor&quot; href=&quot;#huo-yong&quot; aria-label=&quot;Anchor link for: huo-yong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;dong-1-wu-duan-dong-ci&quot;&gt;动1（五段动词）&lt;a class=&quot;zola-anchor&quot; href=&quot;#dong-1-wu-duan-dong-ci&quot; aria-label=&quot;Anchor link for: dong-1-wu-duan-dong-ci&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&quot;ます形&quot;去掉&quot;ます&quot;后的最后一个假名→相应的&quot;あ段&quot;假名 + &quot;ない&quot;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;書きます → 書き → 書かない&lt;&#x2F;li&gt;
&lt;li&gt;急ぎます → 急ぎ → 急がない&lt;&#x2F;li&gt;
&lt;li&gt;行きます → 行き → 行かない&lt;&#x2F;li&gt;
&lt;li&gt;話します → 話し → 話さない&lt;&#x2F;li&gt;
&lt;li&gt;買います → 買わない&lt;&#x2F;li&gt;
&lt;li&gt;会います → 会わない&lt;&#x2F;li&gt;
&lt;li&gt;もらいます → もらわない&lt;&#x2F;li&gt;
&lt;li&gt;あります → ない [例外]&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;dong-2-yi-duan-dong-ci-dong-3-sabian&quot;&gt;动2（一段动词）、动3（サ変）&lt;a class=&quot;zola-anchor&quot; href=&quot;#dong-2-yi-duan-dong-ci-dong-3-sabian&quot; aria-label=&quot;Anchor link for: dong-2-yi-duan-dong-ci-dong-3-sabian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;ます → ない&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;食べます → 食べない&lt;&#x2F;li&gt;
&lt;li&gt;見ます → 見ない&lt;&#x2F;li&gt;
&lt;li&gt;します → しない&lt;&#x2F;li&gt;
&lt;li&gt;勉強します → 勉強しない&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;dong-3-kabian&quot;&gt;动3（カ変）&lt;a class=&quot;zola-anchor&quot; href=&quot;#dong-3-kabian&quot; aria-label=&quot;Anchor link for: dong-3-kabian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;来ます → 来ない（こない）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Japanese | 动词的「た」形</title>
          <pubDate>Mon, 26 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-05-26-japanese-verb-ta/</link>
          <guid>https://inasa.dev/posts/25-05-26-japanese-verb-ta/</guid>
          <description xml:base="https://inasa.dev/posts/25-05-26-japanese-verb-ta/">&lt;p&gt;活用：&quot;て形&quot;的&quot;て&quot;换成&quot;た&quot;，&quot;で&quot;换成&quot;だ&quot;&lt;&#x2F;p&gt;
&lt;p&gt;简单来说，把て形中的：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;て → た&lt;&#x2F;li&gt;
&lt;li&gt;で → だ&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;例如：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;書いて → 書いた&lt;&#x2F;li&gt;
&lt;li&gt;読んで → 読んだ&lt;&#x2F;li&gt;
&lt;li&gt;食べて → 食べた&lt;&#x2F;li&gt;
&lt;li&gt;して → した&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;类别&lt;&#x2F;th&gt;&lt;th&gt;ます形&lt;&#x2F;th&gt;&lt;th&gt;&lt;&#x2F;th&gt;&lt;th&gt;て形&lt;&#x2F;th&gt;&lt;th&gt;&lt;&#x2F;th&gt;&lt;th&gt;た形&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;一类动词&lt;&#x2F;td&gt;&lt;td&gt;書きます（かきます）&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;かいて&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;かいた&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;行きます（いきます）&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;※いって&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;いった&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;急ぎます（いそぎます）&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;いそいで&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;いそいだ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;飛びます（とびます）&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;とんで&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;とんだ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;読みます（よみます）&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;よんで&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;よんだ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;死にます（しにます）&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;しんで&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;しんだ&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;待ちます（まちます）&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;まって&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;まった&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;売ります（うります）&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;うって&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;うった&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;買います（かいます）&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;かって&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;かった&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;二类动词&lt;&#x2F;td&gt;&lt;td&gt;食べます（たべます）&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;たべて&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;たべた&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;見ます（みます）&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;みて&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;みた&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;三类动词&lt;&#x2F;td&gt;&lt;td&gt;来ます（きます）&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;きて&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;きた&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;します（します）&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;して&lt;&#x2F;td&gt;&lt;td&gt;→&lt;&#x2F;td&gt;&lt;td&gt;した&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
</description>
      </item>
      <item>
          <title>Japanese | 动词的「て」形</title>
          <pubDate>Mon, 26 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-05-26-japanese-verb-te/</link>
          <guid>https://inasa.dev/posts/25-05-26-japanese-verb-te/</guid>
          <description xml:base="https://inasa.dev/posts/25-05-26-japanese-verb-te/">&lt;h2 id=&quot;dong-ci-yin-huo-yong-de-bu-tong-fen-san-lei&quot;&gt;动词因活用的不同分三类：&lt;a class=&quot;zola-anchor&quot; href=&quot;#dong-ci-yin-huo-yong-de-bu-tong-fen-san-lei&quot; aria-label=&quot;Anchor link for: dong-ci-yin-huo-yong-de-bu-tong-fen-san-lei&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;dong-1&quot;&gt;动1&lt;a class=&quot;zola-anchor&quot; href=&quot;#dong-1&quot; aria-label=&quot;Anchor link for: dong-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;动1（五段动词）：ます形去掉ます后的最后一个假名位于&quot;い&quot;段的动词&lt;&#x2F;p&gt;
&lt;p&gt;如：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;書きます&lt;&#x2F;li&gt;
&lt;li&gt;読みます　&lt;&#x2F;li&gt;
&lt;li&gt;帰ります&lt;&#x2F;li&gt;
&lt;li&gt;買います&lt;&#x2F;li&gt;
&lt;li&gt;貸します&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;bian-hua-gui-ze&quot;&gt;变化规则&lt;a class=&quot;zola-anchor&quot; href=&quot;#bian-hua-gui-ze&quot; aria-label=&quot;Anchor link for: bian-hua-gui-ze&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;ます形去掉ます后，最后一个假名&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;变化规则&lt;&#x2F;th&gt;&lt;th&gt;例子&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;き → いて&lt;&#x2F;td&gt;&lt;td&gt;• 書きます → 書いて&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ぎ → いで&lt;&#x2F;td&gt;&lt;td&gt;• 急ぎます → 急いで&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;び、み、に → んで&lt;&#x2F;td&gt;&lt;td&gt;• 飛びます → 飛んで&lt;br&gt;• 読みます → 読んで&lt;br&gt;• 死にます → 死んで&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;ち、り、い → って&lt;&#x2F;td&gt;&lt;td&gt;• 待ちます → 待って&lt;br&gt;• 売ります → 売って&lt;br&gt;• 買います → 買って&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;し → して&lt;&#x2F;td&gt;&lt;td&gt;• 話します → 話して&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h4 id=&quot;te-shu-qing-kuang&quot;&gt;特殊情况：&lt;a class=&quot;zola-anchor&quot; href=&quot;#te-shu-qing-kuang&quot; aria-label=&quot;Anchor link for: te-shu-qing-kuang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;行きます → 行って (いって)　　いいて (×)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;dong-2&quot;&gt;动2&lt;a class=&quot;zola-anchor&quot; href=&quot;#dong-2&quot; aria-label=&quot;Anchor link for: dong-2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;动2（一段动词）：ます形去掉ます后的最后一个假名位于&quot;え&quot;段的动词&lt;&#x2F;p&gt;
&lt;p&gt;如：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;食べます&lt;&#x2F;li&gt;
&lt;li&gt;寝ます&lt;&#x2F;li&gt;
&lt;li&gt;かけます&lt;&#x2F;li&gt;
&lt;li&gt;閉めます&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;及一小部分ます形去掉ます后的最后一个假名位于&quot;い&quot;段的动词（初级大约有15个左右）&lt;&#x2F;p&gt;
&lt;p&gt;如：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;起きます&lt;&#x2F;li&gt;
&lt;li&gt;見ます&lt;&#x2F;li&gt;
&lt;li&gt;借ります&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;bian-hua-gui-ze-1&quot;&gt;变化规则&lt;a class=&quot;zola-anchor&quot; href=&quot;#bian-hua-gui-ze-1&quot; aria-label=&quot;Anchor link for: bian-hua-gui-ze-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;变化规则&lt;&#x2F;th&gt;&lt;th&gt;例子&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;ます → て&lt;&#x2F;td&gt;&lt;td&gt;• 食べます → 食べて&lt;br&gt;• 見ます → 見て&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h3 id=&quot;dong-3&quot;&gt;动3&lt;a class=&quot;zola-anchor&quot; href=&quot;#dong-3&quot; aria-label=&quot;Anchor link for: dong-3&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;サ変動詞（使用します的动词），如：
&lt;ul&gt;
&lt;li&gt;します&lt;&#x2F;li&gt;
&lt;li&gt;勉強します&lt;&#x2F;li&gt;
&lt;li&gt;掃除します&lt;&#x2F;li&gt;
&lt;li&gt;コピーします&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;カ変動詞（只有一个）：
&lt;ul&gt;
&lt;li&gt;来ます&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;bian-hua-gui-ze-2&quot;&gt;变化规则&lt;a class=&quot;zola-anchor&quot; href=&quot;#bian-hua-gui-ze-2&quot; aria-label=&quot;Anchor link for: bian-hua-gui-ze-2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;h5 id=&quot;sabian-dong-ci&quot;&gt;サ変動詞&lt;a class=&quot;zola-anchor&quot; href=&quot;#sabian-dong-ci&quot; aria-label=&quot;Anchor link for: sabian-dong-ci&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h5&gt;
&lt;ul&gt;
&lt;li&gt;します → して&lt;&#x2F;li&gt;
&lt;li&gt;勉強します → 勉強して&lt;&#x2F;li&gt;
&lt;li&gt;掃除します → 掃除して&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h5 id=&quot;kabian-dong-ci&quot;&gt;カ変動詞&lt;a class=&quot;zola-anchor&quot; href=&quot;#kabian-dong-ci&quot; aria-label=&quot;Anchor link for: kabian-dong-ci&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h5&gt;
&lt;ul&gt;
&lt;li&gt;来ます → 来て&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;biao-ge-zong-jie&quot;&gt;表格总结&lt;a class=&quot;zola-anchor&quot; href=&quot;#biao-ge-zong-jie&quot; aria-label=&quot;Anchor link for: biao-ge-zong-jie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;类别&lt;&#x2F;th&gt;&lt;th&gt;ます形&lt;&#x2F;th&gt;&lt;th&gt;ます形&lt;&#x2F;th&gt;&lt;th&gt;去掉ます&lt;&#x2F;th&gt;&lt;th&gt;て形&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;一类动词&lt;&#x2F;td&gt;&lt;td&gt;書きます (写)&lt;&#x2F;td&gt;&lt;td&gt;かきます&lt;&#x2F;td&gt;&lt;td&gt;かき&lt;&#x2F;td&gt;&lt;td&gt;かいて&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;※行きます (去)&lt;&#x2F;td&gt;&lt;td&gt;いきます&lt;&#x2F;td&gt;&lt;td&gt;いき&lt;&#x2F;td&gt;&lt;td&gt;いって&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;*急ぎます (急)&lt;&#x2F;td&gt;&lt;td&gt;いそぎます&lt;&#x2F;td&gt;&lt;td&gt;いそぎ&lt;&#x2F;td&gt;&lt;td&gt;いそいで&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;*飛びます (飞)&lt;&#x2F;td&gt;&lt;td&gt;とびます&lt;&#x2F;td&gt;&lt;td&gt;とび&lt;&#x2F;td&gt;&lt;td&gt;とんで&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;読みます (读)&lt;&#x2F;td&gt;&lt;td&gt;よみます&lt;&#x2F;td&gt;&lt;td&gt;よみ&lt;&#x2F;td&gt;&lt;td&gt;よんで&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;*死にます (死)&lt;&#x2F;td&gt;&lt;td&gt;しにます&lt;&#x2F;td&gt;&lt;td&gt;しに&lt;&#x2F;td&gt;&lt;td&gt;しんで&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;*待ちます (等)&lt;&#x2F;td&gt;&lt;td&gt;まちます&lt;&#x2F;td&gt;&lt;td&gt;まち&lt;&#x2F;td&gt;&lt;td&gt;まって&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;*売ります (卖)&lt;&#x2F;td&gt;&lt;td&gt;うります&lt;&#x2F;td&gt;&lt;td&gt;うり&lt;&#x2F;td&gt;&lt;td&gt;うって&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;買います (买)&lt;&#x2F;td&gt;&lt;td&gt;かいます&lt;&#x2F;td&gt;&lt;td&gt;かい&lt;&#x2F;td&gt;&lt;td&gt;かって&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;*話します (说)&lt;&#x2F;td&gt;&lt;td&gt;はなします&lt;&#x2F;td&gt;&lt;td&gt;はなし&lt;&#x2F;td&gt;&lt;td&gt;はなして&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;二类动词&lt;&#x2F;td&gt;&lt;td&gt;食べます (吃)&lt;&#x2F;td&gt;&lt;td&gt;たべます&lt;&#x2F;td&gt;&lt;td&gt;たべ&lt;&#x2F;td&gt;&lt;td&gt;たべて&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;見ます (看)&lt;&#x2F;td&gt;&lt;td&gt;みます&lt;&#x2F;td&gt;&lt;td&gt;み&lt;&#x2F;td&gt;&lt;td&gt;みて&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;三类动词&lt;&#x2F;td&gt;&lt;td&gt;来ます (来)&lt;&#x2F;td&gt;&lt;td&gt;きます&lt;&#x2F;td&gt;&lt;td&gt;き&lt;&#x2F;td&gt;&lt;td&gt;きて&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;&#x2F;td&gt;&lt;td&gt;します (做)&lt;&#x2F;td&gt;&lt;td&gt;します&lt;&#x2F;td&gt;&lt;td&gt;し&lt;&#x2F;td&gt;&lt;td&gt;して&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;※ &quot;行きます&quot; 属于例外，其 &quot;て形&quot; 是 &quot;行って&quot;。&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Japanese | 公司常用的日语寒暄语</title>
          <pubDate>Thu, 22 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-05-22-japanese-aisatsu/</link>
          <guid>https://inasa.dev/posts/25-05-22-japanese-aisatsu/</guid>
          <description xml:base="https://inasa.dev/posts/25-05-22-japanese-aisatsu/">&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;申し訳ありません。&lt;&#x2F;strong&gt; (もうしわけありません - Moushiwake arimasen)&lt;br &#x2F;&gt;
中文：对不起，抱歉。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;どうも。&lt;&#x2F;strong&gt; (どうも - Doumo)&lt;br &#x2F;&gt;
中文：谢谢&#x2F;对不起。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ごめんください。&lt;&#x2F;strong&gt; (ごめんください - Gomen kudasai)&lt;br &#x2F;&gt;
中文：对不起，有人吗？&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;お邪魔します。&lt;&#x2F;strong&gt; (おじゃまします - Ojama shimasu)&lt;br &#x2F;&gt;
中文：打扰了。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;お邪魔しました。&lt;&#x2F;strong&gt; (おじゃましました - Ojama shimashita)&lt;br &#x2F;&gt;
中文：打扰了。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;失礼します。&lt;&#x2F;strong&gt; (しつれいします - Shitsurei shimasu)&lt;br &#x2F;&gt;
中文：打扰了&#x2F;告辞了。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;失礼しました。&lt;&#x2F;strong&gt; (しつれいしました - Shitsurei shimashita)&lt;br &#x2F;&gt;
中文：告辞了&#x2F;失礼了。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;お先に失礼します。&lt;&#x2F;strong&gt; (おさきにしつれいします - Osaki ni shitsurei shimasu)&lt;br &#x2F;&gt;
中文：先告辞了。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;お疲れ様でした。&lt;&#x2F;strong&gt; (おつかれさまでした - Otsukaresama deshita)&lt;br &#x2F;&gt;
中文：辛苦了。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ご苦労様でした。&lt;&#x2F;strong&gt; (ごくろうさまでした - Gokurousama deshita)&lt;br &#x2F;&gt;
中文：辛苦了。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;これからお世話になります。&lt;&#x2F;strong&gt; (これからおせわになります - Kore kara osewa ni narimasu)&lt;br &#x2F;&gt;
中文：今后请多多关照。
&lt;em&gt;适用于初次合作或开始新工作关系时&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;いつもお世話になっております。&lt;&#x2F;strong&gt; (いつもおせわになっております - Itsumo osewa ni natte orimasu)&lt;br &#x2F;&gt;
中文：承蒙多方关照。
&lt;em&gt;表达对持续合作关系的感谢&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;いろいろお世話になりました。&lt;&#x2F;strong&gt; (いろいろおせわになりました - Iroiro osewa ni narimashita)&lt;br &#x2F;&gt;
中文：受到各方面的照顾。
&lt;em&gt;表达对过去帮助的感谢&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;お久しぶりです。&lt;&#x2F;strong&gt; (おひさしぶりです - Ohisashiburi desu)&lt;br &#x2F;&gt;
中文：好久不见。
&lt;em&gt;与久未见面的人重逢时使用&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ご無沙汰しています。&lt;&#x2F;strong&gt; (ごぶさたしています - Gobusata shite imasu)&lt;br &#x2F;&gt;
中文：久疏问候。
&lt;em&gt;较正式的&quot;好久不见&quot;，暗含歉意&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;お大事に。&lt;&#x2F;strong&gt; (おだいじに - Odaiji ni)&lt;br &#x2F;&gt;
中文：请保重。
&lt;em&gt;对生病或不适的人表达关心&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;おかげさまで。&lt;&#x2F;strong&gt; (おかげさまで - Okagesama de)&lt;br &#x2F;&gt;
中文：托您的福。
&lt;em&gt;表达感谢对方关心或帮助，常用于回应&quot;你好吗？&quot;等问候&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</description>
      </item>
      <item>
          <title>Japanese | “ちょっと” 和 “ちょうど”</title>
          <pubDate>Tue, 20 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-05-20-japanese-chotto-choudo/</link>
          <guid>https://inasa.dev/posts/25-05-20-japanese-chotto-choudo/</guid>
          <description xml:base="https://inasa.dev/posts/25-05-20-japanese-chotto-choudo/">&lt;h2 id=&quot;tiyotuto&quot;&gt;ちょっと&lt;a class=&quot;zola-anchor&quot; href=&quot;#tiyotuto&quot; aria-label=&quot;Anchor link for: tiyotuto&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;意思：稍微、有点儿，一般表示数量或程度上的一点点，不太多。&lt;&#x2F;p&gt;
&lt;p&gt;用法更口语化，常用于请求、程度描述、婉转表达。&lt;&#x2F;p&gt;
&lt;p&gt;例子：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ちょっと待ってください。（请稍等一下。）&lt;&#x2F;li&gt;
&lt;li&gt;このケーキはちょっと甘いです。（这个蛋糕有点甜。）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;可以表示“稍微超出预期”或“有点不足”，比较模糊。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tiyoudo&quot;&gt;ちょうど&lt;a class=&quot;zola-anchor&quot; href=&quot;#tiyoudo&quot; aria-label=&quot;Anchor link for: tiyoudo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;意思：正好、恰好，表示完全符合、正合适，没有多余或不足。&lt;&#x2F;p&gt;
&lt;p&gt;用法较正式，强调程度的准确性或时间的恰当。&lt;&#x2F;p&gt;
&lt;p&gt;例子：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;ちょうど５時に着きました。（正好5点到了。）&lt;&#x2F;li&gt;
&lt;li&gt;これはちょうどいい大きさです。（这是正合适的大小。）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;强调精确度和合适度。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zong-jie-qu-bie&quot;&gt;总结区别&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie-qu-bie&quot; aria-label=&quot;Anchor link for: zong-jie-qu-bie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;ちょっと：大致、稍微，带有一定的模糊性和灵活性，口语多用。&lt;&#x2F;li&gt;
&lt;li&gt;ちょうど：完全、准确，表示恰到好处，强调精确和适当。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Japanese | “じゅう”和“なか”</title>
          <pubDate>Tue, 20 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-05-20-japanese-naka-ju/</link>
          <guid>https://inasa.dev/posts/25-05-20-japanese-naka-ju/</guid>
          <description xml:base="https://inasa.dev/posts/25-05-20-japanese-naka-ju/">&lt;h2 id=&quot;zhong-ziyuu&quot;&gt;「〜中（じゅう）」&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhong-ziyuu&quot; aria-label=&quot;Anchor link for: zhong-ziyuu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;这是一个接续词，用在名词后面表示“整个范围内”、“期间全部”。&lt;&#x2F;p&gt;
&lt;p&gt;例如：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;世界 中（せかいじゅう）＝全世界&lt;&#x2F;li&gt;
&lt;li&gt;学校 中（がっこうじゅう）＝全学校范围内&lt;&#x2F;li&gt;
&lt;li&gt;一日 中（いちにちじゅう）＝一整天内&lt;&#x2F;li&gt;
&lt;li&gt;一年 中（いちねんじゅう）＝一整年内&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;这是表示时间或空间“整个范围”的意思。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zhong-naka&quot;&gt;「中（なか）」&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhong-naka&quot; aria-label=&quot;Anchor link for: zhong-naka&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;这是一个名词，表示“里面、中间”的意思。可以单独使用或者和助词结合。&lt;&#x2F;p&gt;
&lt;p&gt;例如：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;箱の 中（はこのなか）＝箱里面&lt;&#x2F;li&gt;
&lt;li&gt;部屋の 中（へやのなか）＝房间里面&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;qu-bie-zong-jie&quot;&gt;区别总结&lt;a class=&quot;zola-anchor&quot; href=&quot;#qu-bie-zong-jie&quot; aria-label=&quot;Anchor link for: qu-bie-zong-jie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;词汇&lt;&#x2F;th&gt;&lt;th&gt;读音&lt;&#x2F;th&gt;&lt;th&gt;词性&lt;&#x2F;th&gt;&lt;th&gt;作用&lt;&#x2F;th&gt;&lt;th&gt;例子&lt;&#x2F;th&gt;&lt;th&gt;意思&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;中&lt;&#x2F;td&gt;&lt;td&gt;じゅう (jū)&lt;&#x2F;td&gt;&lt;td&gt;接续词（后缀）&lt;&#x2F;td&gt;&lt;td&gt;表示整个范围、期间&lt;&#x2F;td&gt;&lt;td&gt;世界中、日本中&lt;&#x2F;td&gt;&lt;td&gt;全世界范围内、整个日本范围内&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;中&lt;&#x2F;td&gt;&lt;td&gt;なか (naka)&lt;&#x2F;td&gt;&lt;td&gt;名词&lt;&#x2F;td&gt;&lt;td&gt;表示“里面”、“当中”&lt;&#x2F;td&gt;&lt;td&gt;箱の中、部屋の中&lt;&#x2F;td&gt;&lt;td&gt;某物体的内部、中间位置&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;「なか」是「中」的另一种用法，和「〜中（じゅう）」是不同的词，表示不同的意思。&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Japanese | 动词て形的相关用法</title>
          <pubDate>Tue, 20 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-05-20-japanese-nan-nani-copy/</link>
          <guid>https://inasa.dev/posts/25-05-20-japanese-nan-nani-copy/</guid>
          <description xml:base="https://inasa.dev/posts/25-05-20-japanese-nan-nani-copy/">&lt;p&gt;动词的 &lt;strong&gt;て形&lt;&#x2F;strong&gt;（て形）是日语中非常重要的动词变形形式，功能多样，应用广泛。主要用途和使用场景包括：&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;1-lian-jie-dong-zuo-xiang-dang-yu-ran-hou-shun-jie&quot;&gt;1. 连接动作，相当于“……然后……”（顺接）&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-lian-jie-dong-zuo-xiang-dang-yu-ran-hou-shun-jie&quot; aria-label=&quot;Anchor link for: 1-lian-jie-dong-zuo-xiang-dang-yu-ran-hou-shun-jie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;多个动作顺序发生时，用て形连接动词。&lt;&#x2F;li&gt;
&lt;li&gt;例：
&lt;ul&gt;
&lt;li&gt;本を &lt;strong&gt;読んで&lt;&#x2F;strong&gt;、宿題をします。&lt;br &#x2F;&gt;
（读书，然后做作业。）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;2-biao-shi-dong-zuo-zheng-zai-jin-xing-teiru&quot;&gt;2. 表示动作正在进行（〜ている）&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-biao-shi-dong-zuo-zheng-zai-jin-xing-teiru&quot; aria-label=&quot;Anchor link for: 2-biao-shi-dong-zuo-zheng-zai-jin-xing-teiru&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;て形＋いる，表示动作正在进行或状态持续。&lt;&#x2F;li&gt;
&lt;li&gt;例：
&lt;ul&gt;
&lt;li&gt;今、テレビを &lt;strong&gt;見ています&lt;&#x2F;strong&gt;。&lt;br &#x2F;&gt;
（现在正在看电视。）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;3-biao-shi-ming-ling-huo-qing-qiu-tekudasai&quot;&gt;3. 表示命令或请求（〜てください）&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-biao-shi-ming-ling-huo-qing-qiu-tekudasai&quot; aria-label=&quot;Anchor link for: 3-biao-shi-ming-ling-huo-qing-qiu-tekudasai&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;て形＋ください，用于请求别人做某事。&lt;&#x2F;li&gt;
&lt;li&gt;例：
&lt;ul&gt;
&lt;li&gt;ここに &lt;strong&gt;座ってください&lt;&#x2F;strong&gt;。&lt;br &#x2F;&gt;
（请坐这里。）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;4-biao-shi-yun-xu-huo-jin-zhi&quot;&gt;4. 表示允许或禁止&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-biao-shi-yun-xu-huo-jin-zhi&quot; aria-label=&quot;Anchor link for: 4-biao-shi-yun-xu-huo-jin-zhi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;动词的て形＋もいい ：表示“可以做……”。&lt;&#x2F;li&gt;
&lt;li&gt;动词的て形＋はいけない ：表示“不可以做……”。&lt;&#x2F;li&gt;
&lt;li&gt;例：
&lt;ul&gt;
&lt;li&gt;写真を撮ってもいいですか？&lt;br &#x2F;&gt;
（可以拍照吗？）&lt;&#x2F;li&gt;
&lt;li&gt;ここでタバコを吸ってはいけません。&lt;br &#x2F;&gt;
（这里不可以吸烟。）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;5-gei-yu-yuan-yin-li-you-te&quot;&gt;5. 给予原因、理由（〜て、）&lt;a class=&quot;zola-anchor&quot; href=&quot;#5-gei-yu-yuan-yin-li-you-te&quot; aria-label=&quot;Anchor link for: 5-gei-yu-yuan-yin-li-you-te&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;て形用于表示原因或理由，相当于“因为……”。&lt;&#x2F;li&gt;
&lt;li&gt;例：
&lt;ul&gt;
&lt;li&gt;熱があって、学校を休みました。&lt;br &#x2F;&gt;
（因为发烧，所以没去学校。）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;6-biao-shi-bing-lie-lie-ju-te&quot;&gt;6. 表示并列，列举（〜て）&lt;a class=&quot;zola-anchor&quot; href=&quot;#6-biao-shi-bing-lie-lie-ju-te&quot; aria-label=&quot;Anchor link for: 6-biao-shi-bing-lie-lie-ju-te&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;て形连接多个动作或状态，表示并列关系。&lt;&#x2F;li&gt;
&lt;li&gt;例：
&lt;ul&gt;
&lt;li&gt;コーヒーを飲んで、新聞を読みます。&lt;br &#x2F;&gt;
（喝咖啡，然后看报纸。）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;7-biao-shi-dong-zuo-de-yi-ge-zhong-zhi-huo-zhuan-zhe-you-shi&quot;&gt;7. 表示动作的一个中止或转折（有时）&lt;a class=&quot;zola-anchor&quot; href=&quot;#7-biao-shi-dong-zuo-de-yi-ge-zhong-zhi-huo-zhuan-zhe-you-shi&quot; aria-label=&quot;Anchor link for: 7-biao-shi-dong-zuo-de-yi-ge-zhong-zhi-huo-zhuan-zhe-you-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;与其他句子结构结合使用，表达转折。&lt;&#x2F;li&gt;
&lt;li&gt;例：
&lt;ul&gt;
&lt;li&gt;急いで行きましたが、間に合いませんでした。&lt;br &#x2F;&gt;
（虽然急忙去，但没赶上。）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;用途&lt;&#x2F;th&gt;&lt;th&gt;说明&lt;&#x2F;th&gt;&lt;th&gt;示例&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;动作顺接&lt;&#x2F;td&gt;&lt;td&gt;动作间顺序连接&lt;&#x2F;td&gt;&lt;td&gt;ご飯を食べて、テレビを見ます。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;动作进行&lt;&#x2F;td&gt;&lt;td&gt;ている表示动作正在进行或状态&lt;&#x2F;td&gt;&lt;td&gt;本を読んでいます。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;请求&lt;&#x2F;td&gt;&lt;td&gt;てください表示请求&lt;&#x2F;td&gt;&lt;td&gt;窓を開けてください。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;允许&#x2F;禁止&lt;&#x2F;td&gt;&lt;td&gt;てもいい（允许）、てはいけない（禁止）&lt;&#x2F;td&gt;&lt;td&gt;ここで写真を撮ってもいいです。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;表示原因、理由&lt;&#x2F;td&gt;&lt;td&gt;因为……&lt;&#x2F;td&gt;&lt;td&gt;熱があって、寝ました。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;并列、列举&lt;&#x2F;td&gt;&lt;td&gt;多个动作或状态的并列&lt;&#x2F;td&gt;&lt;td&gt;コーヒーを飲んで、新聞を読みます。&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
</description>
      </item>
      <item>
          <title>Japanese | “何”的读法</title>
          <pubDate>Tue, 20 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-05-20-japanese-nan-nani/</link>
          <guid>https://inasa.dev/posts/25-05-20-japanese-nan-nani/</guid>
          <description xml:base="https://inasa.dev/posts/25-05-20-japanese-nan-nani/">&lt;p&gt;“何”的读法&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;“なん”&lt;&#x2F;li&gt;
&lt;li&gt;“なに”&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;规则&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;位于辅音t、d、n（た、だ、な行假名）前，念“なん”；位于其他辅音前，念“なに”。&lt;&#x2F;li&gt;
&lt;li&gt;询问性质或种类时，念“なに”；询问数量时，念“なん”。
&lt;ul&gt;
&lt;li&gt;何人 → “なにじん（哪里人）” → “なんにん（多少人）”&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;何（なに）&#x2F;何（なん）&lt;&#x2F;th&gt;&lt;th&gt;助词&lt;&#x2F;th&gt;&lt;th&gt;例句&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;何（なに）&lt;&#x2F;td&gt;&lt;td&gt;と&lt;&#x2F;td&gt;&lt;td&gt;何と 何を 買いますか。（你都买什么和什么？）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;何（なに）&lt;&#x2F;td&gt;&lt;td&gt;が&lt;&#x2F;td&gt;&lt;td&gt;あそこに 何が ありますか。（那儿有什么？）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;何（なに）&lt;&#x2F;td&gt;&lt;td&gt;を&lt;&#x2F;td&gt;&lt;td&gt;何を 食べますか。（你吃什么？）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;何（なに&#x2F;なん）&lt;&#x2F;td&gt;&lt;td&gt;で&lt;&#x2F;td&gt;&lt;td&gt;何で 会社へ 行きますか。（你怎么去公司？）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;何（なん）&lt;&#x2F;td&gt;&lt;td&gt;の&lt;&#x2F;td&gt;&lt;td&gt;それは 何の 本ですか。（那是什么书？）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;何（なん）&lt;&#x2F;td&gt;&lt;td&gt;时刻&#x2F;星期等&lt;&#x2F;td&gt;&lt;td&gt;李さんは 何時に 来ますか。（小李几点来？）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
</description>
      </item>
      <item>
          <title>Japanese | 日本星期的命名</title>
          <pubDate>Mon, 19 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-05-19-japanese-weekdays/</link>
          <guid>https://inasa.dev/posts/25-05-19-japanese-weekdays/</guid>
          <description xml:base="https://inasa.dev/posts/25-05-19-japanese-weekdays/">&lt;p&gt;日本的星期命名系统结合了中国古代的七曜说（以天体命名）和序数系统的特点，这是历史和文化交流的结果。&lt;&#x2F;p&gt;
&lt;p&gt;日本星期的命名有两种主要表达方式：&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tian-ti-ming-ming-fa&quot;&gt;天体命名法&lt;a class=&quot;zola-anchor&quot; href=&quot;#tian-ti-ming-ming-fa&quot; aria-label=&quot;Anchor link for: tian-ti-ming-ming-fa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;日曜日（にちようび）- 太阳日&#x2F;星期日&lt;&#x2F;li&gt;
&lt;li&gt;月曜日（げつようび）- 月亮日&#x2F;星期一&lt;&#x2F;li&gt;
&lt;li&gt;火曜日（かようび）- 火星日&#x2F;星期二&lt;&#x2F;li&gt;
&lt;li&gt;水曜日（すいようび）- 水星日&#x2F;星期三&lt;&#x2F;li&gt;
&lt;li&gt;木曜日（もくようび）- 木星日&#x2F;星期四&lt;&#x2F;li&gt;
&lt;li&gt;金曜日（きんようび）- 金星日&#x2F;星期五&lt;&#x2F;li&gt;
&lt;li&gt;土曜日（どようび）- 土星日&#x2F;星期六&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&quot;日月火水木金土&quot;这个顺序的形成有着深厚的历史渊源：&lt;&#x2F;p&gt;
&lt;p&gt;七曜概念的起源：这个概念最初源自古巴比伦的天文观测，后来传到古埃及、罗马，并经过印度传入中国。&lt;&#x2F;p&gt;
&lt;p&gt;七曜的天体含义：七曜指的是古代可见的七个天体：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;日（太阳）&lt;&#x2F;li&gt;
&lt;li&gt;月（月亮）&lt;&#x2F;li&gt;
&lt;li&gt;火（火星）&lt;&#x2F;li&gt;
&lt;li&gt;水（水星）&lt;&#x2F;li&gt;
&lt;li&gt;木（木星）&lt;&#x2F;li&gt;
&lt;li&gt;金（金星）&lt;&#x2F;li&gt;
&lt;li&gt;土（土星）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;顺序的形成原理：这个排列顺序基于古代的&quot;行星时&quot;概念。在地心说的宇宙模型中，这七个天体按照离地球的距离由远及近排列为：土、木、火、日、金、水、月。&lt;&#x2F;p&gt;
&lt;p&gt;七曜到星期的转换方法：如果将这七个天体按距离排列在一个七角形上，然后按照特定的跳跃方式（每次跳过两个天体）连接，就会形成我们现在的星期顺序。这种算法也被称为&quot;隔二七曜法&quot;。&lt;&#x2F;p&gt;
&lt;p&gt;在古代中国，这种对应关系与五行学说（金木水火土）相结合，形成了完整的宇宙观体系。后来日本、朝鲜等国家也采用了这种七曜命名法来表示一周七天。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;xu-shu-ming-ming-fa&quot;&gt;序数命名法&lt;a class=&quot;zola-anchor&quot; href=&quot;#xu-shu-ming-ming-fa&quot; aria-label=&quot;Anchor link for: xu-shu-ming-ming-fa&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;星期日&lt;&#x2F;li&gt;
&lt;li&gt;星期一&lt;&#x2F;li&gt;
&lt;li&gt;星期二&lt;&#x2F;li&gt;
&lt;li&gt;星期三&lt;&#x2F;li&gt;
&lt;li&gt;星期四&lt;&#x2F;li&gt;
&lt;li&gt;星期五&lt;&#x2F;li&gt;
&lt;li&gt;星期六&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;日本选择这种命名方式体现了日本文化对中国传统的吸收与保留，同时也显示了日本在接受外来文化时的灵活性。现代日本人在日常生活中主要使用天体命名法（曜日系统），这已经成为日语文化的特色之一。&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Economy  | 什么是贸易顺差和贸易逆差？</title>
          <pubDate>Fri, 09 May 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-05-09-economy-trade-surplus-deficit/</link>
          <guid>https://inasa.dev/posts/25-05-09-economy-trade-surplus-deficit/</guid>
          <description xml:base="https://inasa.dev/posts/25-05-09-economy-trade-surplus-deficit/">&lt;h2 id=&quot;mao-yi-shun-chai-trade-surplus&quot;&gt;贸易顺差 (Trade Surplus)&lt;a class=&quot;zola-anchor&quot; href=&quot;#mao-yi-shun-chai-trade-surplus&quot; aria-label=&quot;Anchor link for: mao-yi-shun-chai-trade-surplus&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;贸易顺差是指一个国家或地区在一定时期内(通常是一个月、一个季度或一年)的出口总额大于进口总额的经济现象。简单来说，就是卖出去的多，买进来的少。&lt;&#x2F;p&gt;
&lt;p&gt;贸易顺差的特点:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;外汇储备增加&lt;&#x2F;li&gt;
&lt;li&gt;国内就业机会增多&lt;&#x2F;li&gt;
&lt;li&gt;国内生产总值(GDP)增长&lt;&#x2F;li&gt;
&lt;li&gt;本国货币有升值趋势&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;实例国家:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;中国、德国、日本、韩国等国家长期保持贸易顺差。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;mao-yi-ni-chai-trade-deficit&quot;&gt;贸易逆差 (Trade Deficit)&lt;a class=&quot;zola-anchor&quot; href=&quot;#mao-yi-ni-chai-trade-deficit&quot; aria-label=&quot;Anchor link for: mao-yi-ni-chai-trade-deficit&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;贸易逆差是指一个国家或地区在一定时期内的进口总额大于出口总额的经济现象。简单来说，就是买进来的多，卖出去的少。&lt;&#x2F;p&gt;
&lt;p&gt;贸易逆差的特点:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;外汇储备减少&lt;&#x2F;li&gt;
&lt;li&gt;可能导致本国货币贬值&lt;&#x2F;li&gt;
&lt;li&gt;国内消费能力强&lt;&#x2F;li&gt;
&lt;li&gt;可能增加国家债务&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;实例国家:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;美国、英国、印度等国家常年存在贸易逆差。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;ying-xiang-yin-su&quot;&gt;影响因素&lt;a class=&quot;zola-anchor&quot; href=&quot;#ying-xiang-yin-su&quot; aria-label=&quot;Anchor link for: ying-xiang-yin-su&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;贸易顺差和逆差受多种因素影响:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;汇率水平&lt;&#x2F;li&gt;
&lt;li&gt;国内生产成本&lt;&#x2F;li&gt;
&lt;li&gt;产业结构&lt;&#x2F;li&gt;
&lt;li&gt;贸易政策(关税、补贴等)&lt;&#x2F;li&gt;
&lt;li&gt;国内消费能力&lt;&#x2F;li&gt;
&lt;li&gt;资源禀赋&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;jing-ji-ying-xiang&quot;&gt;经济影响&lt;a class=&quot;zola-anchor&quot; href=&quot;#jing-ji-ying-xiang&quot; aria-label=&quot;Anchor link for: jing-ji-ying-xiang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;贸易顺差和逆差本身并不能简单判断为&quot;好&quot;或&quot;坏&quot;，需要结合一国经济发展阶段、产业结构等多方面因素来评估:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;适度的贸易顺差有利于积累外汇、促进就业&lt;&#x2F;li&gt;
&lt;li&gt;长期过高的顺差可能导致国内消费不足、产业结构失衡&lt;&#x2F;li&gt;
&lt;li&gt;适度的贸易逆差有助于改善国内居民生活水平&lt;&#x2F;li&gt;
&lt;li&gt;长期过高的逆差可能导致外债累积、经济风险增加&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;ju-li&quot;&gt;举例&lt;a class=&quot;zola-anchor&quot; href=&quot;#ju-li&quot; aria-label=&quot;Anchor link for: ju-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;美国对日本存在685亿美元的贸易逆差，而对英国则有119亿美元的贸易顺差。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mei-guo-dui-ri-ben-de-mao-yi-ni-chai&quot;&gt;美国对日本的贸易逆差&lt;a class=&quot;zola-anchor&quot; href=&quot;#mei-guo-dui-ri-ben-de-mao-yi-ni-chai&quot; aria-label=&quot;Anchor link for: mei-guo-dui-ri-ben-de-mao-yi-ni-chai&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;美国从日本进口的商品和服务总价值超过美国向日本出口的总价值，差额达685亿美元&lt;&#x2F;li&gt;
&lt;li&gt;具体来说，美国从日本买入的商品和服务比卖给日本的多685亿美元&lt;&#x2F;li&gt;
&lt;li&gt;资金流动上，美国有685亿美元的净资金流出到日本&lt;&#x2F;li&gt;
&lt;li&gt;这表明日本在对美贸易中处于相对优势地位&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;mei-guo-dui-ying-guo-de-mao-yi-shun-chai&quot;&gt;美国对英国的贸易顺差&lt;a class=&quot;zola-anchor&quot; href=&quot;#mei-guo-dui-ying-guo-de-mao-yi-shun-chai&quot; aria-label=&quot;Anchor link for: mei-guo-dui-ying-guo-de-mao-yi-shun-chai&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;美国向英国出口的商品和服务总价值超过美国从英国进口的总价值，差额达119亿美元&lt;&#x2F;li&gt;
&lt;li&gt;具体来说，美国卖给英国的商品和服务比从英国买入的多119亿美元&lt;&#x2F;li&gt;
&lt;li&gt;资金流动上，美国有119亿美元的净资金流入来自英国&lt;&#x2F;li&gt;
&lt;li&gt;这表明美国在对英贸易中处于相对优势地位&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;zong-he-fen-xi&quot;&gt;综合分析&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-he-fen-xi&quot; aria-label=&quot;Anchor link for: zong-he-fen-xi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;这句话展示了美国与不同国家之间的贸易关系呈现不同状态：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;美国是日本商品的净购买者（买多卖少）&lt;&#x2F;li&gt;
&lt;li&gt;美国是英国商品的净出售者（卖多买少）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;这种差异可能反映了各国产业结构、竞争优势、消费者偏好以及贸易政策的不同。例如，美国消费者可能更偏好日本的电子产品、汽车等，而英国消费者则可能更青睐美国的科技产品、娱乐内容或农产品等。&lt;&#x2F;p&gt;
&lt;p&gt;贸易顺差或逆差本身并不代表经济关系的好坏，而是反映了国家间经济结构和贸易模式的差异。&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Apache Arrow | Primitive Layouts</title>
          <pubDate>Tue, 29 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-29-arrow-format-intro/</link>
          <guid>https://inasa.dev/posts/25-04-29-arrow-format-intro/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-29-arrow-format-intro/">&lt;h2 id=&quot;fixed-size-primitive-layout&quot;&gt;Fixed Size Primitive Layout&lt;a class=&quot;zola-anchor&quot; href=&quot;#fixed-size-primitive-layout&quot; aria-label=&quot;Anchor link for: fixed-size-primitive-layout&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;固定大小的基础数据类型布局,指内存或数据结构中，大小固定的基本类型的排列方式。&lt;&#x2F;p&gt;
&lt;p&gt;原始列表示一个值数组，其中每个值具有相同的物理大小（以字节为单位）。使用固定大小原始布局的数据类型例如有：有符号和无符号整数类型、浮点数、布尔值、小数以及时间类型数据。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;arrow.apache.org&#x2F;docs&#x2F;_images&#x2F;primitive-diagram.svg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;原始数据示例:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;column 1&lt;&#x2F;code&gt; 是整数列，没有空值。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;column 2&lt;&#x2F;code&gt; 是浮点数列，有一个空值（&lt;code&gt;null&lt;&#x2F;code&gt;）。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;内存中的物理布局:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;column 1&lt;&#x2F;code&gt;（整数列）
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Validity bitmap buffer&lt;&#x2F;code&gt;（有效性位图缓冲区）：显示为 &lt;code&gt;None&lt;&#x2F;code&gt;，说明这一列没有空值，所有数据都是有效的，所以不需要额外的位图来记录有效性状态。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Values buffer&lt;&#x2F;code&gt;（值缓冲区）：存储了这列中所有整数的实际值 &lt;code&gt;[1, 3, 9, 9, 2]&lt;&#x2F;code&gt;，这些值是连续存储的，占用固定大小的空间（如每个整数4字节）。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;column 2&lt;&#x2F;code&gt;（浮点数列）
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Validity bitmap buffer&lt;&#x2F;code&gt;（有效性位图缓冲区）：值是 &lt;code&gt;00010111&lt;&#x2F;code&gt;，这是一个二进制序列，用来标记每个值是否有效（&lt;code&gt;1&lt;&#x2F;code&gt;表示有效，&lt;code&gt;0&lt;&#x2F;code&gt;表示无效，即&lt;code&gt;null&lt;&#x2F;code&gt;）。
&lt;ul&gt;
&lt;li&gt;从右往左数（通常位图是从最低位开始代表第一个元素），4 个元素对应的位是：
&lt;ul&gt;
&lt;li&gt;第1个值 &lt;code&gt;1.2&lt;&#x2F;code&gt; — &lt;code&gt;bit&lt;&#x2F;code&gt;为&lt;code&gt;1&lt;&#x2F;code&gt;，有效&lt;&#x2F;li&gt;
&lt;li&gt;第2个值 &lt;code&gt;3.4&lt;&#x2F;code&gt; — &lt;code&gt;bit&lt;&#x2F;code&gt;为&lt;code&gt;1&lt;&#x2F;code&gt;，有效&lt;&#x2F;li&gt;
&lt;li&gt;第3个值 &lt;code&gt;9.0&lt;&#x2F;code&gt; — &lt;code&gt;bit&lt;&#x2F;code&gt;为&lt;code&gt;1&lt;&#x2F;code&gt;，有效&lt;&#x2F;li&gt;
&lt;li&gt;第4个值 &lt;code&gt;null&lt;&#x2F;code&gt; — &lt;code&gt;bit&lt;&#x2F;code&gt;为&lt;code&gt;0&lt;&#x2F;code&gt;，无效&lt;&#x2F;li&gt;
&lt;li&gt;第5个值 &lt;code&gt;2.9&lt;&#x2F;code&gt; — &lt;code&gt;bit&lt;&#x2F;code&gt;为&lt;code&gt;1&lt;&#x2F;code&gt;，有效&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Values buffer&lt;&#x2F;code&gt;（值缓冲区）：存储了非空值 &lt;code&gt;[1.2, 3.4, 9.0, _, 2.9]&lt;&#x2F;code&gt;，第4个元素对应的值空缺（用 &lt;code&gt;_&lt;&#x2F;code&gt; 表示），因为它是空值，具体位置不存储实际数据或可能用某种占位符代替。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;总结：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;固定大小的原始布局中，每个元素占用相同大小的字节，值直接顺序存储在值缓冲区中。&lt;&#x2F;li&gt;
&lt;li&gt;对于有空值的列，用一个有效性位图缓冲区用二进制位标识每一行数据是否有效，节省存储空间并方便快速判断。&lt;&#x2F;li&gt;
&lt;li&gt;没有空值的列则完全不需要有效性位图，直接存储所有值。&lt;&#x2F;li&gt;
&lt;li&gt;这个布局可以高效地存储和访问大量原始数据类型（整数、浮点数等），并支持空值管理。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;布尔类型的数据使用一种原始布局表示，其中数据是以位（&lt;code&gt;bit&lt;&#x2F;code&gt;）而不是字节（&lt;code&gt;byte&lt;&#x2F;code&gt;）进行编码的。这意味着物理布局包括一个值位图缓冲区（&lt;code&gt;values bitmap buffer&lt;&#x2F;code&gt;），并且可能还包含一个有效性位图缓冲区（&lt;code&gt;validity bitmap buffer&lt;&#x2F;code&gt;）。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;arrow.apache.org&#x2F;docs&#x2F;_images&#x2F;bool-diagram.svg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;左边的&lt;code&gt;column 10&lt;&#x2F;code&gt;列包含布尔值：&lt;code&gt;True&lt;&#x2F;code&gt;、&lt;code&gt;True&lt;&#x2F;code&gt;、&lt;code&gt;False&lt;&#x2F;code&gt;、&lt;code&gt;null&lt;&#x2F;code&gt;、&lt;code&gt;False&lt;&#x2F;code&gt;、&lt;code&gt;True&lt;&#x2F;code&gt;。&lt;&#x2F;li&gt;
&lt;li&gt;右边的&lt;code&gt;Validity bitmap buffer&lt;&#x2F;code&gt;用二进制 &lt;code&gt;00110111&lt;&#x2F;code&gt; 表示哪些值是有效的（&lt;code&gt;1&lt;&#x2F;code&gt;表示有效，&lt;code&gt;0&lt;&#x2F;code&gt;表示无效&#x2F;&lt;code&gt;null&lt;&#x2F;code&gt;）。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Values bitmap buffer&lt;&#x2F;code&gt;用二进制 &lt;code&gt;11000100&lt;&#x2F;code&gt; 表示对应位置的布尔值，即&lt;code&gt;True&lt;&#x2F;code&gt;或&lt;code&gt;False&lt;&#x2F;code&gt;的实际值。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;variable-length-binary-and-string&quot;&gt;Variable length binary and string&lt;a class=&quot;zola-anchor&quot; href=&quot;#variable-length-binary-and-string&quot; aria-label=&quot;Anchor link for: variable-length-binary-and-string&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;可变长度的二进制和字符串，指二进制数据和字符串，其长度不是固定的，可以变化。&lt;&#x2F;p&gt;
&lt;p&gt;与固定大小的原始布局相比，可变长度布局允许表示一个数组，其中每个元素的字节大小可以不同。这种布局用于二进制和字符串数据。&lt;&#x2F;p&gt;
&lt;p&gt;二进制或字符串列中所有元素的字节会连续存储在单个缓冲区或内存区域中。为了确定每个元素在列中的起始和结束位置，物理布局还包括整型偏移量。偏移量缓冲区的长度总是比数组元素数量多一个。最后两个偏移量定义了最后一个二进制或字符串元素的起始和结束位置。&lt;&#x2F;p&gt;
&lt;p&gt;二进制和字符串数据类型共享相同的物理布局，它们唯一的区别是字符串类型的数组被假设包含有效的 &lt;code&gt;UTF-8&lt;&#x2F;code&gt; 字符串数据。&lt;&#x2F;p&gt;
&lt;p&gt;二进制&#x2F;字符串与大二进制&#x2F;字符串之间的区别在于偏移量的数据类型。前者使用 &lt;code&gt;int32&lt;&#x2F;code&gt;，后者使用 &lt;code&gt;int64&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;使用 32 位偏移量的数据类型的限制是每个数组的最大大小为 2GB。对于更大的数据，仍可以使用非大类型变体，但这时需要多个数据块（chunk）来存储。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;arrow.apache.org&#x2F;docs&#x2F;_images&#x2F;var-string-diagram.svg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;原始字符串数据:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;这是一个字符串列，其中包含了五个元素。&lt;&#x2F;li&gt;
&lt;li&gt;第四个元素是空值（&lt;code&gt;null&lt;&#x2F;code&gt;）。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;内存中的布局结构:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Validity bitmap buffer&lt;&#x2F;code&gt;（有效性位图缓冲区） : &lt;code&gt;00010111&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;用二进制位表示每个元素是否有效（&lt;code&gt;1&lt;&#x2F;code&gt;表示有效，&lt;code&gt;0&lt;&#x2F;code&gt;表示无效）。&lt;&#x2F;li&gt;
&lt;li&gt;这里的每位代表对应行是否有有效字符串：
&lt;ul&gt;
&lt;li&gt;第1个：&lt;code&gt;&quot;python&quot;&lt;&#x2F;code&gt; —— &lt;code&gt;1&lt;&#x2F;code&gt;（有效）&lt;&#x2F;li&gt;
&lt;li&gt;第2个：&lt;code&gt;&quot;data&quot;&lt;&#x2F;code&gt; —— &lt;code&gt;1&lt;&#x2F;code&gt;（有效）&lt;&#x2F;li&gt;
&lt;li&gt;第3个：&lt;code&gt;&quot;conference&quot;&lt;&#x2F;code&gt; —— &lt;code&gt;1&lt;&#x2F;code&gt;（有效）&lt;&#x2F;li&gt;
&lt;li&gt;第4个：&lt;code&gt;null&lt;&#x2F;code&gt; —— &lt;code&gt;0&lt;&#x2F;code&gt;（无效）&lt;&#x2F;li&gt;
&lt;li&gt;第5个：&lt;code&gt;&quot;Berlin&quot;&lt;&#x2F;code&gt; —— &lt;code&gt;1&lt;&#x2F;code&gt;（有效）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Offsets buffer&lt;&#x2F;code&gt;（偏移量缓冲区） : &lt;code&gt;[0, 6, 10, 20, 20, 26]&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;记录每个字符串的起始和结束字节位置。&lt;&#x2F;li&gt;
&lt;li&gt;偏移量数量比元素多一个，最后两个偏移量表示最后元素的结束位置。&lt;&#x2F;li&gt;
&lt;li&gt;具体分析：
&lt;ul&gt;
&lt;li&gt;第1个字符串 &lt;code&gt;&quot;python&quot;&lt;&#x2F;code&gt; 从字节0开始，到字节6止（长度6）&lt;&#x2F;li&gt;
&lt;li&gt;第2个字符串 &lt;code&gt;&quot;data&quot;&lt;&#x2F;code&gt; 从字节6开始，到字节10止（长度4）&lt;&#x2F;li&gt;
&lt;li&gt;第3个字符串 &lt;code&gt;&quot;conference&quot;&lt;&#x2F;code&gt; 从字节10开始，到字节20止（长度10）&lt;&#x2F;li&gt;
&lt;li&gt;第4个字符串是&lt;code&gt;null&lt;&#x2F;code&gt;，对应的起止位置都是20（长度0）&lt;&#x2F;li&gt;
&lt;li&gt;第5个字符串 &lt;code&gt;&quot;Berlin&quot;&lt;&#x2F;code&gt; 从字节20开始，到字节26止（长度6）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Values buffer&lt;&#x2F;code&gt;（值缓冲区） : &lt;code&gt;&quot;pythondataconferenceBerlin&quot;&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;所有有效字符串的字符数据连接成一个连续的字符序列存储。&lt;&#x2F;li&gt;
&lt;li&gt;空值的位置没有对应字符存储（长度为0），但可以根据偏移量辨识出来。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;总结：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;字符串数据不再是固定字节数，因此需要用偏移量数组来标记每个字符串的位置和长度。&lt;&#x2F;li&gt;
&lt;li&gt;所有字符串的数据连成一个大字符串块存储在值缓冲区中。&lt;&#x2F;li&gt;
&lt;li&gt;有效性位图记录哪些字符串是有效，哪些是空值，方便快速过滤和访问。&lt;&#x2F;li&gt;
&lt;li&gt;这种布局使得存储和访问不同长度的字符串变得高效且紧凑。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;variable-length-binary-and-string-view&quot;&gt;Variable length binary and string view&lt;a class=&quot;zola-anchor&quot; href=&quot;#variable-length-binary-and-string-view&quot; aria-label=&quot;Anchor link for: variable-length-binary-and-string-view&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;可变长度二进制和字符串视图，指对可变长度二进制或字符串数据的视图或映射，通常是一种只读或者轻量级访问方式。&lt;&#x2F;p&gt;
&lt;p&gt;这种布局是可变长度二进制布局的一个替代方案，改编自慕尼黑工业大学（TU Munich）的 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;umbra-db.com&#x2F;&quot;&gt;UmbraDB&lt;&#x2F;a&gt;，并且类似于 DuckDB 和 Velox 中使用的字符串布局（有时也被称为“German strings”）。&lt;&#x2F;p&gt;
&lt;p&gt;与传统的二进制和字符串布局相比，主要区别在于“views buffer”（视图缓冲区）。该缓冲区包含字符串的长度，以及字符串本身的字符——对于短字符串，它们以内联形式出现；对于较长字符串，视图缓冲区只包含字符串的前 4 个字节和一个偏移量，指向可能存在的多个数据缓冲区之一。由于它使用偏移量和长度来引用数据缓冲区，所有元素的字节不需要连续存储在单一缓冲区中。这使得可以对可变长度元素进行乱序写入到数组中。&lt;&#x2F;p&gt;
&lt;p&gt;这些特性对于高效的字符串处理非常重要。字符串的前缀（prefix）提供了一条有利且快速的路径，用于字符串比较，而字符串比较通常只需检查前四个字节。元素的选择是对固定宽度“views buffer”进行简单的“聚合”操作（gather），无需重写值缓冲区，从而提高了处理效率。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;arrow.apache.org&#x2F;docs&#x2F;_images&#x2F;var-string-view-diagram.svg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;原始字符串数据:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Column 5&lt;&#x2F;code&gt; 有5个字符串：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&quot;String longer than 12&quot;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&quot;Short&quot;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;null&lt;&#x2F;code&gt;（空值）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&quot;Short string&quot;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&quot;Another long string&quot;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Column 6&lt;&#x2F;code&gt; 也有5个字符串：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&quot;Another long string&quot;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&quot;String longer than 12&quot;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;null&lt;&#x2F;code&gt;（空值）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&quot;Short string&quot;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&quot;pythondataconference&quot;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;内存中的布局结构:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Validity bitmap buffer&lt;&#x2F;code&gt;（有效性位图缓冲区）
&lt;ul&gt;
&lt;li&gt;以位（&lt;code&gt;bit&lt;&#x2F;code&gt;）形式标识每个元素是否有效（&lt;code&gt;1&lt;&#x2F;code&gt; 表示有效，&lt;code&gt;0&lt;&#x2F;code&gt; 表示无效或 &lt;code&gt;null&lt;&#x2F;code&gt;）。&lt;&#x2F;li&gt;
&lt;li&gt;例如 &lt;code&gt;Column 5&lt;&#x2F;code&gt; 和 &lt;code&gt;Column 6&lt;&#x2F;code&gt; 有效性位图都是 &lt;code&gt;00011011&lt;&#x2F;code&gt;，对应第四个元素是 &lt;code&gt;null&lt;&#x2F;code&gt;（0）。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Views buffer&lt;&#x2F;code&gt;（视图缓冲区）
&lt;ul&gt;
&lt;li&gt;视图缓冲区采用固定宽度结构，包含了每个字符串元素的元数据，关键字段包括：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;length&lt;&#x2F;code&gt;（长度）：字符串长度（单位是字节）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;data&lt;&#x2F;code&gt;（数据）：样例字符串或“短字符串”的字符&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;prefix&lt;&#x2F;code&gt;（前缀）：字符串的前几个字节（用于快速比较）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;buffer index&lt;&#x2F;code&gt;（缓冲区索引）：指出字符串内容存储在哪个值缓冲区（&lt;code&gt;values buffer&lt;&#x2F;code&gt;）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;offset&lt;&#x2F;code&gt;（偏移）：字符串内容在对应缓冲区中的起始位置&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Column 5&lt;&#x2F;code&gt; 的举例说明：
&lt;ul&gt;
&lt;li&gt;第一个元素 &lt;code&gt;&quot;String longer than 12&quot;&lt;&#x2F;code&gt; 长度是 21
&lt;ul&gt;
&lt;li&gt;前缀为空（表示不是内联短字符串）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;buffer index&lt;&#x2F;code&gt; 是 0（对应第一个 &lt;code&gt;values buffer&lt;&#x2F;code&gt;）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;offset&lt;&#x2F;code&gt; 是 0（从缓冲区的起始位置开始）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;第二个元素 &lt;code&gt;&quot;Short&quot;&lt;&#x2F;code&gt; 长度是 5
&lt;ul&gt;
&lt;li&gt;是短字符串，内联存储在数据字段，数据字段直接是 &lt;code&gt;&quot;Short&quot;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;buffer index&lt;&#x2F;code&gt; 和 &lt;code&gt;offset&lt;&#x2F;code&gt; 对应空或不适用&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;其他字符串按此类推。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Column 6&lt;&#x2F;code&gt; 的举例说明：
&lt;ul&gt;
&lt;li&gt;第一个元素 &lt;code&gt;&quot;Another long string&quot;&lt;&#x2F;code&gt; 长度为 19，存储在 &lt;code&gt;buffer index&lt;&#x2F;code&gt; 0，从 &lt;code&gt;offset&lt;&#x2F;code&gt; 21 开始。&lt;&#x2F;li&gt;
&lt;li&gt;最后一个字符串 &lt;code&gt;&quot;pythondataconference&quot;&lt;&#x2F;code&gt; 存储在 &lt;code&gt;buffer index&lt;&#x2F;code&gt; 1，&lt;code&gt;offset&lt;&#x2F;code&gt; 0。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;由于 &lt;code&gt;buffer index&lt;&#x2F;code&gt; 和 &lt;code&gt;offset&lt;&#x2F;code&gt; 的存在，可以支持多个 &lt;code&gt;values buffer&lt;&#x2F;code&gt;，不需要所有字符串连续存储。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Values buffers&lt;&#x2F;code&gt;（值缓冲区）
&lt;ul&gt;
&lt;li&gt;存储所有字符串数据的原始字符内容。&lt;&#x2F;li&gt;
&lt;li&gt;多个缓冲区存在时，&lt;code&gt;buffer index&lt;&#x2F;code&gt; 用于区分是哪个缓冲区。&lt;&#x2F;li&gt;
&lt;li&gt;例如，&lt;code&gt;Column 5&lt;&#x2F;code&gt; 只有一个缓冲区：
&lt;ul&gt;
&lt;li&gt;存储 &lt;code&gt;&quot;String longer than 12Another long string&quot;&lt;&#x2F;code&gt; 连续字符串。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Column 6&lt;&#x2F;code&gt; 则有两个缓冲区：
&lt;ul&gt;
&lt;li&gt;第0缓冲区存储 &lt;code&gt;&quot;String longer than 12Another long string&quot;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;第1缓冲区存储 &lt;code&gt;&quot;pythondataconferenceBerlin&quot;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;总结&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;有效性位图 标记哪些字符串是有效的，哪些是 &lt;code&gt;null&lt;&#x2F;code&gt;。&lt;&#x2F;li&gt;
&lt;li&gt;视图缓冲区 用固定宽度结构存储字符串长度、内联短字符串数据（节省空间）、字符串前缀、缓冲区索引、偏移量等元信息。&lt;&#x2F;li&gt;
&lt;li&gt;值缓冲区 是存储所有字符串字符数据的地方，可以存在多个，支持乱序访问和写入。&lt;&#x2F;li&gt;
&lt;li&gt;该设计减少了必须连续存储字符串带来的限制，提高了灵活性和并发处理能力。&lt;&#x2F;li&gt;
&lt;li&gt;前缀字段优化了字符串比较操作，通常只需检查前几个字节即可快速判定。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;1-bu-ju-jie-gou-de-bu-tong&quot;&gt;1. &lt;strong&gt;布局结构的不同&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-bu-ju-jie-gou-de-bu-tong&quot; aria-label=&quot;Anchor link for: 1-bu-ju-jie-gou-de-bu-tong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Variable length binary and string layout（变长二进制&#x2F;字符串布局）&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;使用**Offsets buffer（偏移量缓冲区）**记录每个字符串的起止位置，所有字符串的字节数据连续存储在一个或多个Values buffer中。&lt;&#x2F;li&gt;
&lt;li&gt;偏移量数组长度是元素数加一，用来定义每个字符串的区间。&lt;&#x2F;li&gt;
&lt;li&gt;所有字符串数据必须按顺序紧密排列存储。&lt;&#x2F;li&gt;
&lt;li&gt;有效性通过Validity bitmap控制。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Variable-size Binary View Layout（变长二进制视图布局，也称为string view布局）&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;采用了一个新的结构称为&lt;strong&gt;Views buffer（视图缓冲区）&lt;&#x2F;strong&gt;，用于存储每个字符串的元信息。&lt;&#x2F;li&gt;
&lt;li&gt;Views buffer 中每个元素是固定宽度的结构，包含：字符串长度、字符串前缀（prefix）、buffer index（数据缓冲区索引）、offset（偏移）、甚至可能直接内联存储短字符串数据。&lt;&#x2F;li&gt;
&lt;li&gt;允许将字符串数据存储在多个不连续的Values buffers中，根据buffer index和offset定位具体字符串。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;不要求字符串数据连续存储&lt;&#x2F;strong&gt;，支持乱序写入。&lt;&#x2F;li&gt;
&lt;li&gt;同样有Validity bitmap控制有效性。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;2-dui-zi-fu-chuan-cun-chu-he-fang-wen-de-ying-xiang&quot;&gt;2. &lt;strong&gt;对字符串存储和访问的影响&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-dui-zi-fu-chuan-cun-chu-he-fang-wen-de-ying-xiang&quot; aria-label=&quot;Anchor link for: 2-dui-zi-fu-chuan-cun-chu-he-fang-wen-de-ying-xiang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;变长二进制&#x2F;字符串布局&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;优点：实现简单，字符串按顺序存储，偏移量直接定位。&lt;&#x2F;li&gt;
&lt;li&gt;缺点：字符串元素的访问写入时，必须维护串联的连续存储，&lt;strong&gt;不支持乱序插入或修改&lt;&#x2F;strong&gt;。&lt;&#x2F;li&gt;
&lt;li&gt;对大数据或并发操作灵活性差。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;视图布局&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;由于视图缓冲区的固定宽度记录，可以方便地&lt;strong&gt;快速访问长度和前缀信息&lt;&#x2F;strong&gt;。&lt;&#x2F;li&gt;
&lt;li&gt;允许字符串分散存储在多个缓冲区，且不必顺序写入。&lt;&#x2F;li&gt;
&lt;li&gt;支持字符串的乱序写入和灵活的数据组织。&lt;&#x2F;li&gt;
&lt;li&gt;前缀缓存加快字符串比较和处理效率。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;3-zi-fu-chuan-chu-li-you-hua&quot;&gt;3. &lt;strong&gt;字符串处理优化&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#3-zi-fu-chuan-chu-li-you-hua&quot; aria-label=&quot;Anchor link for: 3-zi-fu-chuan-chu-li-you-hua&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;在视图布局中，&lt;strong&gt;字符串的前缀&lt;&#x2F;strong&gt;（prefix）被专门存储，用于快速字节级比较，这意味着对字符串的相等性或排序判断可以先比较前几个字节而不用完整访问字符串，大幅提升比较速度。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;变长布局则没有这个前缀优化，比较字符串时需要访问完整字符串。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;4-zong-jie-bi-jiao&quot;&gt;4. &lt;strong&gt;总结比较&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#4-zong-jie-bi-jiao&quot; aria-label=&quot;Anchor link for: 4-zong-jie-bi-jiao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;特性&lt;&#x2F;th&gt;&lt;th&gt;变长二进制&#x2F;字符串布局&lt;&#x2F;th&gt;&lt;th&gt;视图布局（string view）&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;元数据存储方式&lt;&#x2F;td&gt;&lt;td&gt;偏移量数组（Offsets buffer）&lt;&#x2F;td&gt;&lt;td&gt;固定宽度视图缓冲区（Views buffer）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;字符串数据位置&lt;&#x2F;td&gt;&lt;td&gt;连续存储在一个或多个Values buffer中&lt;&#x2F;td&gt;&lt;td&gt;分布在多个Values buffer，需buffer index和offset定位&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;是否要求数据连续&lt;&#x2F;td&gt;&lt;td&gt;是&lt;&#x2F;td&gt;&lt;td&gt;否，支持乱序写入&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;支持短字符串优化&lt;&#x2F;td&gt;&lt;td&gt;否&lt;&#x2F;td&gt;&lt;td&gt;是，短字符串可内联存储于视图缓冲区&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;支持快速字符串比较&lt;&#x2F;td&gt;&lt;td&gt;无内置前缀 (Prefix) 优化&lt;&#x2F;td&gt;&lt;td&gt;有，视图缓冲区存储字符串前缀，支持快速比较&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;适用场景&lt;&#x2F;td&gt;&lt;td&gt;简单，适合顺序访问和写入&lt;&#x2F;td&gt;&lt;td&gt;复杂，适合需要高性能随机访问、高并发写入、字符串比较优化的场景&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;实现复杂度&lt;&#x2F;td&gt;&lt;td&gt;较低&lt;&#x2F;td&gt;&lt;td&gt;较高&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;hr &#x2F;&gt;
&lt;h3 id=&quot;zong-jie&quot;&gt;总结&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;“Variable length binary and string layout”&lt;&#x2F;strong&gt; 更简单、直观，数据连续，适合顺序访问。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;“Variable-size Binary View Layout”&lt;&#x2F;strong&gt; 则是一个更灵活、更高效的方案，适合复杂应用，支持多缓冲区、乱序写入和前缀优化，特别在高性能数据库或分析系统中会用到。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;如果你需要，我可以帮你整理一个更图文并茂的对比说明。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;arrow.apache.org&#x2F;docs&#x2F;format&#x2F;Intro.html&quot;&gt;https:&#x2F;&#x2F;arrow.apache.org&#x2F;docs&#x2F;format&#x2F;Intro.html&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | SSTable and Log Structured Storage: LevelDB</title>
          <pubDate>Tue, 29 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-29-sstable-and-log-structured-storage-leveldb/</link>
          <guid>https://inasa.dev/posts/25-04-29-sstable-and-log-structured-storage-leveldb/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-29-sstable-and-log-structured-storage-leveldb/">&lt;p&gt;如果说Protocol Buffers 是谷歌（Google）中个人数据记录的通用语言（lingua franca），那么排序字符串表（Sorted String Table，简称 SSTable）就是用于存储、处理和交换数据集的最受欢迎的输出格式之一。正如其名称所暗示的，SSTable 是一种简单的抽象，用于高效地存储大量键值对，同时优化高吞吐量的顺序读&#x2F;写工作负载。&lt;&#x2F;p&gt;
&lt;p&gt;不幸的是，SSTable 这个名称本身也被业界过度使用，用来指代远远超出排序表本身的服务，这只会增加对本质上非常简单且有用的数据结构的混淆。接下来让我们仔细看看 SSTable 的内部结构，以及 LevelDB 如何利用它。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sstable-sorted-string-table&quot;&gt;SSTable: Sorted String Table&lt;a class=&quot;zola-anchor&quot; href=&quot;#sstable-sorted-string-table&quot; aria-label=&quot;Anchor link for: sstable-sorted-string-table&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;想象一下，我们需要处理一个输入数据量达到数千兆字节（Gigabytes）或数万亿字节（Terabytes）的大型工作负载。此外，我们还需要对其执行多个步骤，每个步骤必须由不同的二进制程序完成——换句话说，想象我们正在运行一系列 Map-Reduce 任务！由于输入数据量庞大，数据的读写操作可能会成为运行时间的瓶颈。因此，随机读写不是一个可行的选项，我们更希望以流式方式读取数据，处理完成后再以流式操作将数据刷新回磁盘。通过这种方式，我们可以摊销磁盘 I&#x2F;O 成本。没有什么革命性的，只是在顺利推进而已。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.igvita.com&#x2F;posts&#x2F;12&#x2F;xsstable.png.pagespeed.ic.IkMoqaKZX9.webp&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;“排序字符串表”（Sorted String Table）顾名思义，就是一个文件，里面包含一组任意的、已排序的键值对。允许存在重复的键，不需要对键或值进行“填充”，键和值都是任意的数据块。顺序读取整个文件，就相当于拥有了一个排序索引。可选地，如果文件非常大，我们还可以在前面添加或创建一个独立的 key:offset 索引，以实现快速访问。SSTable 就是这样一个东西：非常简单，但也是一种非常有用的方式，用于交换大型排序好的数据片段。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sstable-and-bigtable-fast-random-access&quot;&gt;SSTable and BigTable: Fast random access?&lt;a class=&quot;zola-anchor&quot; href=&quot;#sstable-and-bigtable-fast-random-access&quot; aria-label=&quot;Anchor link for: sstable-and-bigtable-fast-random-access&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;一旦 SSTable 存储到磁盘上，它实际上是不可变的，因为插入或删除操作将需要对整个文件进行大量的 I&#x2F;O 重写。不过，对于静态索引来说，这是一种很好的解决方案：读取索引，你总是只需进行一次磁盘查找，或者简单地将整个文件映射到内存中（mmap）。随机读取操作既快速又简单。&lt;&#x2F;p&gt;
&lt;p&gt;而随机写入则要困难且昂贵得多，除非整个表都存放在内存中，这时我们就可以回到简单的指针操作。事实证明，这正是 Google 的 BigTable 试图解决的问题：如何针对规模达到 PB 级的数据集实现快速的读写访问，并且底层依靠的是 SSTable。他们是怎么做到的呢？&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sstables-and-log-structured-merge-trees&quot;&gt;SSTables and Log Structured Merge Trees&lt;a class=&quot;zola-anchor&quot; href=&quot;#sstables-and-log-structured-merge-trees&quot; aria-label=&quot;Anchor link for: sstables-and-log-structured-merge-trees&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;我们希望保留 SSTable 带来的快速读取访问，同时也希望支持快速的随机写入。事实证明，我们已经具备了所有必要的条件：当 SSTable 在内存中时（我们称之为 MemTable），随机写入是快速的；如果表是不可变的，那么存储在磁盘上的 SSTable 也同样可以快速读取。现在，让我们介绍以下约定：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.igvita.com&#x2F;posts&#x2F;12&#x2F;xmemtable-sstable.png.pagespeed.ic.086A_X2TFe.webp&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;磁盘上的 SSTable 索引总是被加载到内存中&lt;&#x2F;li&gt;
&lt;li&gt;所有写入操作直接写入 MemTable 索引&lt;&#x2F;li&gt;
&lt;li&gt;读取操作先检查 MemTable，然后再检查 SSTable 索引&lt;&#x2F;li&gt;
&lt;li&gt;定期将 MemTable 刷写到磁盘，形成 SSTable&lt;&#x2F;li&gt;
&lt;li&gt;定期将磁盘上的多个 SSTable 进行“合并”&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;我们这里做了什么？写入操作总是在内存中进行，因此速度总是很快。一旦 MemTable 达到一定大小，就会被刷新到磁盘，形成一个不可变的 SSTable。然而，我们会将所有 SSTable 索引都保存在内存中，这意味着每次读取时，我们可以先检查 MemTable，然后依次查找 SSTable 索引序列来定位数据。事实证明，我们刚刚重新发明了由 Patrick O&#x27;Neil 描述的“日志结构合并树”（&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;nosqlsummer.org&#x2F;paper&#x2F;lsm-tree&quot;&gt;The Log-Structured Merge-Tree，LSM Tree&lt;&#x2F;a&gt;），这也是 Google “&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;BigTable#Design&quot;&gt;BigTable Tablets&lt;&#x2F;a&gt;” 背后的核心机制。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lsm-sstables-updates-deletes-and-maintenance&quot;&gt;LSM &amp;amp; SSTables: Updates, Deletes and Maintenance&lt;a class=&quot;zola-anchor&quot; href=&quot;#lsm-sstables-updates-deletes-and-maintenance&quot; aria-label=&quot;Anchor link for: lsm-sstables-updates-deletes-and-maintenance&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;这种“LSM”架构带来了许多有趣的特性：写入操作始终快速（只追加写入），而随机读取要么直接从内存中提供，要么只需一次快速的磁盘查找。那么，更新和删除操作该怎么办呢？&lt;&#x2F;p&gt;
&lt;p&gt;一旦 SSTable 存储到磁盘上，它就是不可变的，因此更新和删除操作无法直接修改数据。相反，最近的值会存储在 MemTable 中以便更新，而删除操作则会追加一个“墓碑”（tombstone）记录。由于我们按顺序检查索引，后续的读取会找到更新后的数据或墓碑记录，而不会访问旧的数据。最后，磁盘上存在数百个 SSTable 也不是一个好主意，因此我们会定期运行一个合并过程，将磁盘上的 SSTable 合并，在这个过程中，更新和删除的记录会覆盖并移除旧的数据。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sstables-and-leveldb&quot;&gt;SSTables and LevelDB&lt;a class=&quot;zola-anchor&quot; href=&quot;#sstables-and-leveldb&quot; aria-label=&quot;Anchor link for: sstables-and-leveldb&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;取一个 SSTable，加入一个 MemTable，并应用一套处理约定，你就得到了一个适合某些特定工作负载的优秀数据库引擎。实际上，Google 的 BigTable、Hadoop 的 HBase 和 Cassandra 等系统，都是使用这种架构的变体或直接拷贝。&lt;&#x2F;p&gt;
&lt;p&gt;表面上看很简单，但实现细节非常重要。幸运的是，Jeff Dean 和 Sanjay Ghemawat，这两位 Google SSTable 和 BigTable 基础设施的主要贡献者，于去年早些时候发布了 LevelDB，这基本上是上述架构的一个精确复制版本，具有以下特点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;底层使用 SSTable，写操作通过 MemTable 完成&lt;&#x2F;li&gt;
&lt;li&gt;键和值都是任意的字节数组&lt;&#x2F;li&gt;
&lt;li&gt;支持 Put、Get、Delete 操作&lt;&#x2F;li&gt;
&lt;li&gt;支持数据的前向和反向迭代&lt;&#x2F;li&gt;
&lt;li&gt;内置 Snappy 压缩&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;LevelDB 被设计为 WebKit 中 IndexDB 的引擎（即嵌入在你的浏览器中），具有易于嵌入、速度快的特点，最重要的是，它自动处理所有 SSTable 和 MemTable 的刷新、合并及其他复杂细节。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;working-with-leveldb-ruby&quot;&gt;Working with LevelDB: Ruby&lt;a class=&quot;zola-anchor&quot; href=&quot;#working-with-leveldb-ruby&quot; aria-label=&quot;Anchor link for: working-with-leveldb-ruby&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;LevelDB 是一个库，而不是独立的服务器或服务——虽然你完全可以在它之上轻松实现一个。要开始使用，可以获取你喜欢的语言绑定（ruby），接下来让我们看看能做些什么：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;ruby&quot; class=&quot;language-ruby z-code&quot;&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;&lt;span class=&quot;z-meta z-require z-ruby&quot;&gt;&lt;span class=&quot;z-keyword z-other z-special-method z-ruby&quot;&gt;require&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-ruby&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ruby&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;leveldb&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ruby&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ruby&quot;&gt;#&lt;&#x2F;span&gt; gem install leveldb-ruby
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;db &lt;span class=&quot;z-keyword z-operator z-assignment z-ruby&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-class z-ruby&quot;&gt;LevelDB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-ruby&quot;&gt;::&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-class z-ruby&quot;&gt;DB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-ruby&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-other z-special-method z-ruby&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-ruby&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;tmp&#x2F;db&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;db&lt;span class=&quot;z-punctuation z-accessor z-dot z-ruby&quot;&gt;.&lt;&#x2F;span&gt;put &lt;span class=&quot;z-meta z-string z-ruby&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;b&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-ruby&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-ruby&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;bar&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;db&lt;span class=&quot;z-punctuation z-accessor z-dot z-ruby&quot;&gt;.&lt;&#x2F;span&gt;put &lt;span class=&quot;z-meta z-string z-ruby&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-ruby&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-ruby&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;foo&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;db&lt;span class=&quot;z-punctuation z-accessor z-dot z-ruby&quot;&gt;.&lt;&#x2F;span&gt;put &lt;span class=&quot;z-meta z-string z-ruby&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;c&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-sequence z-ruby&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-ruby&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;baz&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-ruby&quot;&gt;puts&lt;&#x2F;span&gt; db&lt;span class=&quot;z-punctuation z-accessor z-dot z-ruby&quot;&gt;.&lt;&#x2F;span&gt;get &lt;span class=&quot;z-meta z-string z-ruby&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-definition z-string z-end z-ruby&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ruby&quot;&gt;#&lt;&#x2F;span&gt; =&amp;gt; foo
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;db&lt;span class=&quot;z-punctuation z-accessor z-dot z-ruby&quot;&gt;.&lt;&#x2F;span&gt;each &lt;span class=&quot;z-keyword z-control z-start-block z-ruby&quot;&gt;do&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-parameters z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-begin z-ruby&quot;&gt;|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-parameters z-ruby&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-ruby&quot;&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-ruby&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-ruby&quot;&gt;v&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-parameters z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameters z-end z-ruby&quot;&gt;|&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt; &lt;span class=&quot;z-support z-function z-builtin z-ruby&quot;&gt;p&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-array z-ruby&quot;&gt;[&lt;&#x2F;span&gt;k&lt;span class=&quot;z-punctuation z-separator z-sequence z-ruby&quot;&gt;,&lt;&#x2F;span&gt;v&lt;span class=&quot;z-punctuation z-section z-array z-ruby&quot;&gt;]&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ruby&quot;&gt;#&lt;&#x2F;span&gt; =&amp;gt; [&amp;quot;a&amp;quot;, &amp;quot;foo&amp;quot;], [&amp;quot;b&amp;quot;, &amp;quot;bar&amp;quot;], [&amp;quot;c&amp;quot;, &amp;quot;baz&amp;quot;]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;&lt;span class=&quot;z-keyword z-control z-ruby&quot;&gt;end&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-ruby&quot;&gt;db&lt;span class=&quot;z-punctuation z-accessor z-dot z-ruby&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-builtin z-ruby&quot;&gt;to_a&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-ruby&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-ruby&quot;&gt;#&lt;&#x2F;span&gt; =&amp;gt; [[&amp;quot;a&amp;quot;, &amp;quot;foo&amp;quot;], [&amp;quot;b&amp;quot;, &amp;quot;bar&amp;quot;], [&amp;quot;c&amp;quot;, &amp;quot;baz&amp;quot;]]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;我们可以用几行代码来存储键、检索键以及执行范围扫描。MemTable 的维护、SSTable 的合并等其他工作都由 LevelDB 负责处理——既简洁又方便。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;leveldb-in-webkit-and-beyond&quot;&gt;LevelDB in WebKit and Beyond&lt;a class=&quot;zola-anchor&quot; href=&quot;#leveldb-in-webkit-and-beyond&quot; aria-label=&quot;Anchor link for: leveldb-in-webkit-and-beyond&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;SSTable 是一种非常简单且实用的数据结构，是一种优秀的大批量输入&#x2F;输出格式。然而，使 SSTable 快速（有序且不可变）的特性也暴露出它的一些局限性。为了解决这些问题，我们引入了 MemTable 的概念，以及一套用于管理众多 SSTable 的“日志结构”处理约定。&lt;&#x2F;p&gt;
&lt;p&gt;这些都是简单的规则，但如往常一样，实现细节非常重要，这也是为什么 LevelDB 能成为开源数据库引擎栈中的一个优秀补充。很可能，你很快就在浏览器、手机以及许多其他地方发现 LevelDB 的身影。你可以查看 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;leveldb&#x2F;source&#x2F;browse&#x2F;&quot;&gt;LevelDB 的源码&lt;&#x2F;a&gt;，&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;leveldb.googlecode.com&#x2F;svn&#x2F;trunk&#x2F;doc&#x2F;index.html&quot;&gt;浏览文档&lt;&#x2F;a&gt;，并亲自试用一下。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.igvita.com&#x2F;2012&#x2F;02&#x2F;06&#x2F;sstable-and-log-structured-storage-leveldb&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.igvita.com&#x2F;2012&#x2F;02&#x2F;06&#x2F;sstable-and-log-structured-storage-leveldb&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>日语 | 日语中的音读和训读</title>
          <pubDate>Mon, 28 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-28-japanese-onyomi-kunyomi/</link>
          <guid>https://inasa.dev/posts/25-04-28-japanese-onyomi-kunyomi/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-28-japanese-onyomi-kunyomi/">&lt;p&gt;日语中的汉字有两种主要的读法系统：音读（On&#x27;yomi，音読み）和训读（Kun&#x27;yomi，訓読み）。这是日语文字系统的独特特点，理解它们的区别对学习日语很重要。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;yin-du-on-yomi-yin-du-mi&quot;&gt;音读（On&#x27;yomi，音読み）&lt;a class=&quot;zola-anchor&quot; href=&quot;#yin-du-on-yomi-yin-du-mi&quot; aria-label=&quot;Anchor link for: yin-du-on-yomi-yin-du-mi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;音读是指汉字从中国传入日本时，按照当时中国的发音或者类似发音读出来的方式。即借用汉字在原来中文中的发音，加以日本化。
和中文发音有相似之处，经常用于合成词（即“熟语”）。&lt;&#x2F;p&gt;
&lt;p&gt;特点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;源自古代中国语音&lt;&#x2F;li&gt;
&lt;li&gt;通常用于汉字组成的复合词中&lt;&#x2F;li&gt;
&lt;li&gt;一个汉字可能有多种音读&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;xun-du-kun-yomi-xun-du-mi&quot;&gt;训读（Kun&#x27;yomi，訓読み）&lt;a class=&quot;zola-anchor&quot; href=&quot;#xun-du-kun-yomi-xun-du-mi&quot; aria-label=&quot;Anchor link for: xun-du-kun-yomi-xun-du-mi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;训读是汉字传入日本后，日本人根据自己本来的日语意思和发音，赋予这个汉字本土的读音。
表现日本本土语言的意思和发音，经常用于单独使用时，特别是和助词连用时。&lt;&#x2F;p&gt;
&lt;p&gt;特点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;源自原始日语词汇&lt;&#x2F;li&gt;
&lt;li&gt;通常用于单独使用的汉字或与假名（ひらがな）结合时&lt;&#x2F;li&gt;
&lt;li&gt;常表达基本概念和日常用语&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;liang-zhe-de-qu-bie-ju-li&quot;&gt;两者的区别举例&lt;a class=&quot;zola-anchor&quot; href=&quot;#liang-zhe-de-qu-bie-ju-li&quot; aria-label=&quot;Anchor link for: liang-zhe-de-qu-bie-ju-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;以&quot;山&quot;（山）这个汉字为例：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;音读：サン (san)，如在&quot;火山&quot;（かざん，kazan，火山）中&lt;&#x2F;li&gt;
&lt;li&gt;训读：やま (yama)，当单独表示&quot;山&quot;时&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;以&quot;水&quot;（水）为例：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;音读：スイ (sui)，如在&quot;水泳&quot;（すいえい，suiei，游泳）中&lt;&#x2F;li&gt;
&lt;li&gt;训读：みず (mizu)，当单独表示&quot;水&quot;时&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;区别&lt;&#x2F;th&gt;&lt;th&gt;音读（On’yomi）&lt;&#x2F;th&gt;&lt;th&gt;训读（Kun’yomi）&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;来源&lt;&#x2F;td&gt;&lt;td&gt;汉语发音的借用&lt;&#x2F;td&gt;&lt;td&gt;日本固有语的发音&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;用法&lt;&#x2F;td&gt;&lt;td&gt;合成词&#x2F;熟语&lt;&#x2F;td&gt;&lt;td&gt;单个词、和假名组合&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;读音举例&lt;&#x2F;td&gt;&lt;td&gt;学（がく）、校（こう）&lt;&#x2F;td&gt;&lt;td&gt;学ぶ（まなぶ）、山（やま）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;是否较通用&lt;&#x2F;td&gt;&lt;td&gt;对应中文名词&lt;&#x2F;td&gt;&lt;td&gt;对应日语表达&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
</description>
      </item>
      <item>
          <title>转载 | 防止在 Go 中意外复制结构</title>
          <pubDate>Mon, 28 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-28-preventing-accidental-struct-ccopies-in-go/</link>
          <guid>https://inasa.dev/posts/25-04-28-preventing-accidental-struct-ccopies-in-go/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-28-preventing-accidental-struct-ccopies-in-go/">&lt;p&gt;默认情况下，Go 语言在传递值时会进行复制。但有时候这种复制并不理想。例如，如果你不小心复制了一个互斥锁（&lt;code&gt;mutex&lt;&#x2F;code&gt;），并且多个 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 分别使用复制出来的锁实例，那么它们之间就不能正确同步。在这种情况下，传递指向锁的指针可以避免复制，从而按预期工作。&lt;&#x2F;p&gt;
&lt;p&gt;举个例子：按值传递一个 &lt;code&gt;sync.WaitGroup&lt;&#x2F;code&gt; 会以微妙的方式导致问题发生：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;wg&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;sync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;WaitGroup&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; ... do something with the waitgroup
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;wg&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;sync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;WaitGroup&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-function z-go&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;wg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; oops! wg is getting copied here!
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;sync.WaitGroup&lt;&#x2F;code&gt; 让你等待多个 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 完成一些工作。在其内部，它是一个带有 &lt;code&gt;Add&lt;&#x2F;code&gt;、&lt;code&gt;Done&lt;&#x2F;code&gt; 和 &lt;code&gt;Wait&lt;&#x2F;code&gt; 等方法的结构体，用于同步并发运行的 &lt;code&gt;goroutine&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;这段代码虽然可以正常编译，但会导致错误的行为，因为我们在 &lt;code&gt;f&lt;&#x2F;code&gt; 函数中复制了锁，而不是引用它。&lt;&#x2F;p&gt;
&lt;p&gt;幸运的是，&lt;code&gt;go vet&lt;&#x2F;code&gt; 工具能够检测到这个问题。如果你对这段代码运行 &lt;code&gt;go vet&lt;&#x2F;code&gt;，你会收到类似如下的警告：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; passes lock by value: sync.WaitGroup contains sync.noCopy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;call&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; of f copies lock value: sync.WaitGroup contains sync.noCopy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这意味着我们错误地按值传递了 &lt;code&gt;wg&lt;&#x2F;code&gt;，而实际上应该传递它的引用。下面是修正方法：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;wg&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;sync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;WaitGroup&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; pass by reference
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; ... do something with the waitgroup
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;wg&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;sync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;WaitGroup&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-function z-go&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;wg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; pass a pointer to wg
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;由于这种错误的复制不会导致编译时错误，如果你跳过了 &lt;code&gt;go vet&lt;&#x2F;code&gt;，可能永远也无法发现它。这也是你应该始终使用 &lt;code&gt;go vet&lt;&#x2F;code&gt; 进行代码检查的另一个原因。&lt;&#x2F;p&gt;
&lt;p&gt;我很好奇 Go 工具链是如何强制执行这一点的。线索就在 &lt;code&gt;vet&lt;&#x2F;code&gt; 的警告中：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;call&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; of f copies lock value: sync.WaitGroup contains sync.noCopy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;所以，&lt;code&gt;sync.WaitGroup&lt;&#x2F;code&gt; 里面的 &lt;code&gt;sync.noCopy&lt;&#x2F;code&gt; 结构体在你按值传递时会做一些操作，以提醒 &lt;code&gt;go vet&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;查看 &lt;code&gt;sync.WaitGroup&lt;&#x2F;code&gt; 的实现，你会看到：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;WaitGroup&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;noCopy&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;state&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;atomic&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Uint64&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;sema&lt;&#x2F;span&gt;  &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uint32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;然后我追踪了 &lt;code&gt;noCopy&lt;&#x2F;code&gt; 在 &lt;code&gt;sync&#x2F;cond.go&lt;&#x2F;code&gt; 中的定义。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; noCopy may be added to structs which must not be copied
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; after the first use.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Note that it must not be embedded, due to the Lock and Unlock methods.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Lock is a no-op used by -copylocks checker from `go vet`.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Lock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;   &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Unlock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;只要在 &lt;code&gt;noCopy&lt;&#x2F;code&gt; 上定义空操作的 &lt;code&gt;Lock&lt;&#x2F;code&gt; 和 &lt;code&gt;Unlock&lt;&#x2F;code&gt; 方法就足够了。这实现了 &lt;code&gt;Locker&lt;&#x2F;code&gt; 接口。然后，如果你把这个结构体放到另一个结构体里，&lt;code&gt;go vet&lt;&#x2F;code&gt; 会标记那些试图复制外层结构体的情况。&lt;&#x2F;p&gt;
&lt;p&gt;另外，注意注释：不要将 &lt;code&gt;noCopy&lt;&#x2F;code&gt; 嵌入（embed）进去，而是要显式地包含它。嵌入会将 &lt;code&gt;Lock&lt;&#x2F;code&gt; 和 &lt;code&gt;Unlock&lt;&#x2F;code&gt; 方法暴露到外层结构体上，而这通常不是你想要的。&lt;&#x2F;p&gt;
&lt;p&gt;Go 工具链通过 &lt;code&gt;-copylocks&lt;&#x2F;code&gt; 检查器来强制执行这一点。它是 &lt;code&gt;go vet&lt;&#x2F;code&gt; 的一部分。你可以用 &lt;code&gt;go vet -copylocks .&#x2F;...&lt;&#x2F;code&gt; 专门调用它。它会查找任何嵌套了带有 &lt;code&gt;Lock&lt;&#x2F;code&gt; 和 &lt;code&gt;Unlock&lt;&#x2F;code&gt; 方法结构体的值复制情况。不管那些方法实际做什么，只要有就足够了。&lt;&#x2F;p&gt;
&lt;p&gt;运行 &lt;code&gt;vet&lt;&#x2F;code&gt; 时，它会遍历抽象语法树（&lt;code&gt;AST&lt;&#x2F;code&gt;），并对赋值、函数调用、返回值、结构字面量、&lt;code&gt;range&lt;&#x2F;code&gt; 循环、&lt;code&gt;channel&lt;&#x2F;code&gt; 发送等几乎所有值可能被复制的地方应用这个检查器。如果发现你复制了带有 &lt;code&gt;noCopy&lt;&#x2F;code&gt; 的结构体，它就会警告你。你可以在这里看到检查实现。&lt;&#x2F;p&gt;
&lt;p&gt;有趣的是，如果你定义的 &lt;code&gt;noCopy&lt;&#x2F;code&gt; 不是一个结构体，但实现了 &lt;code&gt;Locker&lt;&#x2F;code&gt; 接口，vet 会忽略它。我在 Go 1.24 上测试过这一点。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;     &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; this is valid but vet doesn&amp;#39;t get triggered
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Lock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;   &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Unlock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这不会触发 &lt;code&gt;vet&lt;&#x2F;code&gt; 警告。只有当 &lt;code&gt;noCopy&lt;&#x2F;code&gt; 是结构体时才有效。原因是 &lt;code&gt;vet&lt;&#x2F;code&gt; 在检查何时触发警告时采用了一个捷径。它目前明确地只查找满足 &lt;code&gt;Locker&lt;&#x2F;code&gt; 接口的结构体类型，即使其他类型也实现了该接口，&lt;code&gt;vet&lt;&#x2F;code&gt; 也会忽略。&lt;&#x2F;p&gt;
&lt;p&gt;你在 &lt;code&gt;sync&lt;&#x2F;code&gt; 包的其他部分也会看到这种做法。&lt;code&gt;sync.Mutex&lt;&#x2F;code&gt; 就用了同样的技巧：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Mutex&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;mu&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;isync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Mutex&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;与 &lt;code&gt;sync.Once&lt;&#x2F;code&gt; 相同:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Once&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;done&lt;&#x2F;span&gt;   &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uint32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;m&lt;&#x2F;span&gt;      &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Mutex&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;noCopy&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;下面是一个完整的示例，展示如何滥用 &lt;code&gt;-copylocks&lt;&#x2F;code&gt; 来防止复制我们自己的结构体：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Svc&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-other z-inherited-class z-go&quot;&gt;noCopy&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Lock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;   &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Unlock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Use this
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;svc&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Svc&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;svc&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; go vet will complain about this copy op
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;运行 &lt;code&gt;go vet&lt;&#x2F;code&gt; 会得到以下结果：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;assignment&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;copies&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;lock&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;to&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;play&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Svc&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;contains&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;play&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;call&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;of&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Println&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;copies&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;lock&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;play&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Svc&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;contains&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;play&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;有人在 Reddit 上问我，究竟是什么触发了 &lt;code&gt;go vet&lt;&#x2F;code&gt; 中 &lt;code&gt;copylock&lt;&#x2F;code&gt; 检查器——是结构体字面量的名字 &lt;code&gt;noCopy&lt;&#x2F;code&gt;，还是它实现了 &lt;code&gt;Locker&lt;&#x2F;code&gt; 接口？&lt;&#x2F;p&gt;
&lt;p&gt;名字 &lt;code&gt;noCopy&lt;&#x2F;code&gt; 并没有特别的意义。你可以随意命名它。只要它实现了 &lt;code&gt;Locker&lt;&#x2F;code&gt; 接口，如果包含它的结构体被复制，&lt;code&gt;go vet&lt;&#x2F;code&gt; 就会发出警告。详见这个 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;go.dev&#x2F;play&#x2F;p&#x2F;M-vR6nOn00j&quot;&gt;Go Playground 代码片段&lt;&#x2F;a&gt;。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;rednafi.com&#x2F;go&#x2F;prevent_struct_copies&#x2F;&quot;&gt;https:&#x2F;&#x2F;rednafi.com&#x2F;go&#x2F;prevent_struct_copies&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | 5 分钟内解释每种缓存策略</title>
          <pubDate>Sun, 27 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-27-caching-strategy-in-5-min/</link>
          <guid>https://inasa.dev/posts/25-04-27-caching-strategy-in-5-min/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-27-caching-strategy-in-5-min/">&lt;h2 id=&quot;cache-aside-lazy-loading&quot;&gt;Cache-Aside (Lazy Loading)&lt;a class=&quot;zola-anchor&quot; href=&quot;#cache-aside-lazy-loading&quot; aria-label=&quot;Anchor link for: cache-aside-lazy-loading&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;这可以说是你最常遇到的一种方式。使用 Cache-Aside 模式时，应用程序代码直接负责管理缓存。当需要数据时，应用程序会先检查缓存中是否存在该数据。如果缓存命中（cache hit），数据会立即返回；如果缓存未命中（cache miss），应用程序会从主数据源（比如数据库）获取数据，将数据副本存入缓存以备下次使用，然后再返回数据。&lt;&#x2F;p&gt;
&lt;p&gt;举个例子，假设要获取某个用户的个人主页：应用程序先检查缓存中是否有 user:123 的数据。如果没有，它会查询数据库、将结果存入缓存 key 为 user:123 的位置，然后再继续后续操作。&lt;&#x2F;p&gt;
&lt;p&gt;适用场景：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;你的工作负载主要是以读操作为主。&lt;&#x2F;li&gt;
&lt;li&gt;偶尔出现过期数据是可以接受的（例如数据库发生了变化，但没有做缓存失效处理）。&lt;&#x2F;li&gt;
&lt;li&gt;你更倾向于在应用程序中保持缓存交互逻辑的简单性。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;cachingstrategy&#x2F;cache-aside.png&quot; alt=&quot;cache-aside.png&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;read-through&quot;&gt;Read-Through&lt;a class=&quot;zola-anchor&quot; href=&quot;#read-through&quot; aria-label=&quot;Anchor link for: read-through&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;在 Read-Through 策略中，应用程序在读取数据时只与缓存交互，将缓存视为主要的数据源。背后的“魔法”是在于：如果请求的数据不在缓存中（即缓存未命中），缓存系统会负责从底层数据库获取数据，存储数据，然后再返回给应用程序。这大大简化了应用程序代码，因为它不需要专门编写从数据库读取数据的逻辑。&lt;&#x2F;p&gt;
&lt;p&gt;举个例子，假设有一个产品目录服务，使用了带有 CacheLoader 的缓存库。应用程序只需调用 cache.get(&quot;product:xyz&quot;)，缓存系统会在缓存未命中的时候自动处理与数据库的交互。&lt;&#x2F;p&gt;
&lt;p&gt;适用场景：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;你的工作负载主要是以读取操作为主。&lt;&#x2F;li&gt;
&lt;li&gt;你希望将数据获取逻辑从主应用流程中抽象出来。&lt;&#x2F;li&gt;
&lt;li&gt;你选用的缓存提供方（比如某些库或托管服务）明确支持这种自动数据加载功能。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;cachingstrategy&#x2F;read-through.png&quot; alt=&quot;read-through.png&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;write-through&quot;&gt;Write-Through&lt;a class=&quot;zola-anchor&quot; href=&quot;#write-through&quot; aria-label=&quot;Anchor link for: write-through&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;在 Write-Through 策略中，一致性至关重要。当你的应用需要写入或更新数据时，它会同时在两个地方操作：缓存和数据库。只有当这两个存储都成功确认写入后，操作才被视为完成。这保证了缓存始终与数据库保持一致，减少了返回过期数据的可能性。&lt;&#x2F;p&gt;
&lt;p&gt;一个典型的例子是关键更新，比如更改用户的电子邮件地址。应用会确保新邮箱同时保存到缓存和数据库，然后再确认操作成功。其权衡是写入延迟可能会更高，因为需要等待两次操作完成。&lt;&#x2F;p&gt;
&lt;p&gt;适用场景：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;当数据一致性至关重要，不能容忍缓存与数据库之间存在差异，并且可以接受稍微降低写入性能作为权衡时，使用该策略。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;cachingstrategy&#x2F;write-through.png&quot; alt=&quot;write-through.png&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;write-behind-write-back&quot;&gt;Write-Behind (Write-Back)&lt;a class=&quot;zola-anchor&quot; href=&quot;#write-behind-write-back&quot; aria-label=&quot;Anchor link for: write-behind-write-back&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;需要极快的写入速度？Write-Behind 可能是你的答案。在这种策略下，应用程序只写入缓存，缓存几乎立即确认写入操作。之后缓存负责将数据异步写回数据库，通常是在短暂延迟后或通过批量写入的方式完成。这大大提升了从应用角度看写入的性能。&lt;&#x2F;p&gt;
&lt;p&gt;这种方式非常适合高频率更新的场景，比如页面浏览计数器、社交媒体的“点赞”，或实时游戏分数等对速度要求极高的应用。不过，这也存在风险：如果缓存未将数据持久化到数据库之前发生故障，数据可能会丢失。&lt;&#x2F;p&gt;
&lt;p&gt;适用场景：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;当写入性能是首要考虑，应用会产生突发写入，并且能够容忍在异步写入完成前缓存发生故障时可能导致的少量数据丢失风险。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;cachingstrategy&#x2F;write-behind.png&quot; alt=&quot;write-behind.png&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;write-around&quot;&gt;Write-Around&lt;a class=&quot;zola-anchor&quot; href=&quot;#write-around&quot; aria-label=&quot;Anchor link for: write-around&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;有时，在写入操作中涉及缓存是不必要的，甚至是有害的。Write-Around 策略通过让应用程序直接将数据写入数据库，完全绕过缓存来解决这个问题。数据只有在后续被读取时（通常使用 Cache-Aside 模式进行读操作）才会进入缓存。&lt;&#x2F;p&gt;
&lt;p&gt;比如批量数据导入或密集日志记录。将这些数据直接写入数据库可以避免向缓存灌入可能很少或不会立即访问的信息，从而让缓存更专注于更“热”、更相关的数据。&lt;&#x2F;p&gt;
&lt;p&gt;适用场景：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;当你有写入量大的工作负载，且数据在写入后不太可能被立即读取，同时你希望避免用可能的“冷”数据污染缓存时，适合使用该策略。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;cachingstrategy&#x2F;write-around.png&quot; alt=&quot;write-around.png&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.swequiz.com&#x2F;blog&#x2F;every-caching-strategy-explained-in-5-minutes&quot;&gt;https:&#x2F;&#x2F;www.swequiz.com&#x2F;blog&#x2F;every-caching-strategy-explained-in-5-minutes&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | 优化Golang中的堆分配:案例研究</title>
          <pubDate>Sun, 27 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-27-optimizing-heap-allocations-in-golang/</link>
          <guid>https://inasa.dev/posts/25-04-27-optimizing-heap-allocations-in-golang/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-27-optimizing-heap-allocations-in-golang/">&lt;p&gt;我参与开发 Dolt，这是第一个具有类似 git 版本控制功能的 SQL 数据库，完全用 Go 语言编写。通常来说，数据库需要非常快速。因此，我们在持续集成（CI）工作流中做了大量测试，以便在代码合并到主分支之前监控性能回退。&lt;&#x2F;p&gt;
&lt;p&gt;上个月，一次本应无操作（no-op）的重构提交，导致 sysbench 的 &lt;code&gt;types_scan&lt;&#x2F;code&gt; 基准测试性能回退了 30%。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;www.dolthub.com&#x2F;blog&#x2F;static&#x2F;1dca0f483d9b83bb63e095add97ee028&#x2F;3126c&#x2F;github-sysbench-results.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;这次更改涉及一个名为 &lt;code&gt;ImmutableValue&lt;&#x2F;code&gt; 的类型，它表示内容哈希，一个包含该哈希数据的可选字节缓冲区，以及一个 &lt;code&gt;ValueStore&lt;&#x2F;code&gt; 接口，该接口可以将内容哈希解析为二进制大对象（&lt;code&gt;binary blobs&lt;&#x2F;code&gt;）。&lt;code&gt;ImmutableValue&lt;&#x2F;code&gt; 有一个 &lt;code&gt;GetBytes&lt;&#x2F;code&gt; 方法，会检查二进制大对象是否已经加载，如果还没有加载，则使用 &lt;code&gt;ValueStore&lt;&#x2F;code&gt; 将其加载到缓冲区中，然后返回该缓冲区。重构的部分目标是将有关 &lt;code&gt;ValueStore&lt;&#x2F;code&gt; 如何解析哈希的具体实现细节隐藏起来，通过将这些细节移动到接口方法中实现。&lt;&#x2F;p&gt;
&lt;p&gt;下面是经过清理的原始 &lt;code&gt;GetBytes&lt;&#x2F;code&gt; 实现版本：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;t&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ImmutableValue&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;GetBytes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Buf&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;      &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;load&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;      &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;          &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;      &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Buf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;t&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ImmutableValue&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;load&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Addr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;IsEmpty&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Buf&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;      &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;  &lt;span class=&quot;z-variable z-function z-go&quot;&gt;WalkNodes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;valueStore&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;h&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Node&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;IsLeaf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Buf&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;append&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;buf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;GetValue&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;以下是新的实现的一个简化版本：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;t&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ImmutableValue&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;GetBytes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Buf&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Addr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;IsEmpty&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Buf&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Buf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;buf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;valueStore&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;ReadBytes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Addr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Buf&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;buf&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Buf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Assert that nodeStore implements ValueStore
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;ValueStore&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;nodeStore&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;nodeStore&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;  &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;chunkStore&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;WalkNodes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;h&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;hash&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Hash&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;cb&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;CallbackFunc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;  &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Other fields removed for simplicity
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;vs&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;nodeStore&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;ReadBytes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;h&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;hash&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Hash&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;result&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;vs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;chunkStore&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;WalkNodes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;h&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Node&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;IsLeaf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-variable z-other z-go&quot;&gt;result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;append&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;GetValue&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;result&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;性能分析显示，新的 &lt;code&gt;ReadBytes&lt;&#x2F;code&gt; 方法有三分之一的运行时间花在调用 &lt;code&gt;runtime.newobject&lt;&#x2F;code&gt; 上，这是 Go 用来在堆上分配内存的内置函数。而这种分配仅在新的实现中发生。&lt;&#x2F;p&gt;
&lt;p&gt;根据以上情况，这个练习有两个问题需要思考：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;额外的内存分配发生在哪里？&lt;&#x2F;li&gt;
&lt;li&gt;为什么这次分配发生在堆上？为什么不在栈上发生？&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;解决方法如下：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;vs&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;nodeStore&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;ReadBytes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;h&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;hash&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Hash&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;result&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;vs&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;nodeStore&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;ReadBytes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;h&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;hash&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Hash&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;result&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;一个字符的改变导致了性能差异达 30%。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;value-receivers-vs-pointer-receivers&quot;&gt;Value Receivers vs Pointer Receivers&lt;a class=&quot;zola-anchor&quot; href=&quot;#value-receivers-vs-pointer-receivers&quot; aria-label=&quot;Anchor link for: value-receivers-vs-pointer-receivers&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Go 不是一门面向对象的语言。它没有继承或抽象类，实际上它根本不存在类。它具有动态分发功能，但仅限于接口。&lt;&#x2F;p&gt;
&lt;p&gt;Go 确实有方法（&lt;code&gt;methods&lt;&#x2F;code&gt;），它们指定一个接收者类型，并且可以在该类型的值上调用。方法不仅用于实现接口，也充当函数的命名空间。因此，忽略接口的情况下，&lt;code&gt;func (receiver ReceiverType) Foo(param ParamType)&lt;&#x2F;code&gt; 等价于 &lt;code&gt;func ReceiverType.Foo(receiver ReceiverType, b ParamType)&lt;&#x2F;code&gt;，并且具有以下额外特性：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;ReceiverType&lt;&#x2F;code&gt; 必须是值类型（即不是指针也不是接口的类型），或者是指向值类型的指针。该值类型称为方法的基础类型。所以，如果基础类型是 &lt;code&gt;T&lt;&#x2F;code&gt;，那么接收者可以是 &lt;code&gt;T&lt;&#x2F;code&gt; 或 &lt;code&gt;*T&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;对于基础类型 &lt;code&gt;T&lt;&#x2F;code&gt;（意味着接收者类型是 &lt;code&gt;T&lt;&#x2F;code&gt; 或 &lt;code&gt;*T&lt;&#x2F;code&gt;），表达式 &lt;code&gt;a.Foo&lt;&#x2F;code&gt; 是有效的，前提是 &lt;code&gt;a&lt;&#x2F;code&gt; 是 &lt;code&gt;T&lt;&#x2F;code&gt; 或 &lt;code&gt;*T&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;这意味着以下所有方式都是调用方法的有效写法：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;ReceiverType&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;  &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;s&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;receiver&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;ReceiverType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;ValueReceiver&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;  &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;called ValueReceiver(&lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;)&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;receiver&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;receiver&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ReceiverType&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;PointerReceiver&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;called PointerReceiver(&lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;)&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;receiver&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;value&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;ReceiverType&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;value&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;pointer&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ReceiverType&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;pointer&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;  &lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;ValueReceiver&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 1) This is equivalent to ReceiverType.ValueReceiver(value)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;  &lt;span class=&quot;z-variable z-other z-go&quot;&gt;value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;PointerReceiver&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 2) This is equivalent to ReceiverType.PointerReceiver(&amp;amp;value)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;  &lt;span class=&quot;z-variable z-other z-go&quot;&gt;pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;PointerReceive&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 3) This is equivalent to ReceiverType.PointerReceive(pointer)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;  &lt;span class=&quot;z-variable z-other z-go&quot;&gt;pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;ValueReceiver&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 4) This is equivalent to ReceiverType.ValueReceiver(*pointer)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;注意，选项4涉及对接收者进行解引用，并将该值作为函数参数传递。这意味着接收者的值会被复制。&lt;&#x2F;p&gt;
&lt;p&gt;这就是我们对第一个问题的回答：因为 &lt;code&gt;ReadBytes&lt;&#x2F;code&gt; 方法使用的是值接收者，每次调用时都会创建一个新的 &lt;code&gt;nodeStore&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;但问题不仅仅是调用方法时会复制参数：在像 Go 这样按值传递的语言中，函数参数总是会被复制。但通常这些副本存在于栈上，在栈上创建值的开销相对较小。问题在于这些副本是创建在堆上，且即使是很小的堆分配，当数量庞大时，也会造成较大的开销。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;stack-allocation-vs-heap-allocation&quot;&gt;Stack Allocation vs Heap Allocation&lt;a class=&quot;zola-anchor&quot; href=&quot;#stack-allocation-vs-heap-allocation&quot; aria-label=&quot;Anchor link for: stack-allocation-vs-heap-allocation&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;在许多语言中，是否在栈上还是堆上创建某个对象通常是显而易见的。例如在 C++ 中，函数参数和局部变量总是在栈上，唯一进行堆分配的方式是显式使用像 &lt;code&gt;new&lt;&#x2F;code&gt; 这样的关键字。这种程度的控制可以使程序性能更可预测，但也容易导致出现指向已释放内存的指针。下面是一个 C++ 的例子：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;cpp&quot; class=&quot;language-cpp z-code&quot;&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-include z-c++&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-include z-c++&quot;&gt;#include&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-other z-lt-gt z-include z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c++&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;iostream&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c++&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-include z-c++&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-include z-c++&quot;&gt;#include&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-other z-lt-gt z-include z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c++&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;string&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c++&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-c++&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-c++&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c++&quot;&gt;getPointer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c++&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-c++&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c++&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c++&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-return z-c++&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c++&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-c++&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c++&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c++&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c++&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c++&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;  &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt; ptr1 &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c++&quot;&gt;&lt;span class=&quot;z-variable z-function z-c++&quot;&gt;getPointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c++&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c++&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c++&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;  &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt; ptr2 &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-c++&quot;&gt;&lt;span class=&quot;z-variable z-function z-c++&quot;&gt;getPointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c++&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c++&quot;&gt;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c++&quot;&gt;&lt;span class=&quot;z-meta z-group z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c++&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;  std&lt;span class=&quot;z-punctuation z-accessor z-double-colon z-c++&quot;&gt;::&lt;&#x2F;span&gt;cout &lt;span class=&quot;z-keyword z-operator z-arithmetic z-c&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;ptr1&lt;span class=&quot;z-punctuation z-terminator z-c++&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c++&quot;&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c++&quot;&gt;&lt;span class=&quot;z-meta z-block z-c++&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c++&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;运行上述代码会打印“2”，而不是你可能预期的“1”。这是因为函数参数 &lt;code&gt;x&lt;&#x2F;code&gt; 存在于栈上，并且在 &lt;code&gt;getPointer&lt;&#x2F;code&gt; 函数返回后立即不复存在。该内存随后被重新用于后续调用，导致被指向的内存被新的栈帧覆盖。&lt;&#x2F;p&gt;
&lt;p&gt;对于从 C++ 转到 Go 的人来说，最令人惊讶的部分之一是，等效的 Go 代码是完全安全且正确的。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;GetPointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;x&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;x&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;ptr1&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;GetPointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;ptr2&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;GetPointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ptr1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;第一次调用中创建的指针依然有效，尽管它指向的是一个已经不存在的栈帧中的函数参数。这看起来像魔法，但其实不是：这里对 &lt;code&gt;x&lt;&#x2F;code&gt; 的引用是有效的，因为 &lt;code&gt;x&lt;&#x2F;code&gt; 被分配到了堆上。Go 编译器允许将局部变量分配到堆上，这也包括函数参数。在这种情况下，编译器推断出指向 &lt;code&gt;x&lt;&#x2F;code&gt; 的指针会比函数调用存在的时间更长，因此它保证该值被分配在堆上，以确保指针保持有效。&lt;&#x2F;p&gt;
&lt;p&gt;在我们的实际代码中，&lt;code&gt;vs&lt;&#x2F;code&gt; 接收者值就是在堆上分配的。但为什么会这样呢？你如何影响 Go 是将变量分配在堆上还是栈上？&lt;&#x2F;p&gt;
&lt;p&gt;不幸的是，你无法做到这一点。如果语言能够让编译器知道某个变量必须分配在栈上，并且在无法满足时强制编译时错误，那将会很不错。但 Go 并没有提供这样的机制。栈分配和堆分配的概念在语言里甚至不存在。用户预计不需要关心它……当然，直到你在进行性能优化时，才必须关注它。&lt;&#x2F;p&gt;
&lt;p&gt;所以，让我们带着这个问题来看一看我们的代码。新复制的接收者值被存储在变量 &lt;code&gt;vs&lt;&#x2F;code&gt; 中。这个内存是否可能存在时间比 &lt;code&gt;GetBytes&lt;&#x2F;code&gt; 调用还长的指针？&lt;&#x2F;p&gt;
&lt;p&gt;下面是函数以及 &lt;code&gt;nodeStore&lt;&#x2F;code&gt; 类型定义：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;nodeStore&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;  &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;chunkStore&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;WalkNodes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;h&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;hash&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Hash&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;cb&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;CallbackFunc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;  &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;  &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Other fields removed for simplicity
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;vs&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;nodeStore&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;ReadBytes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;h&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;hash&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Hash&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;result&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;vs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;chunkStore&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;WalkNodes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;h&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Node&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;IsLeaf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-variable z-other z-go&quot;&gt;result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;append&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;GetValue&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;result&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;我们看到在方法调用 &lt;code&gt;vs.chunkstore.WalkNodes&lt;&#x2F;code&gt; 时，&lt;code&gt;vs&lt;&#x2F;code&gt; 被解引用。理论上，像这样的调用点可能会导致引用泄漏：如果 &lt;code&gt;chunkstore&lt;&#x2F;code&gt; 是值类型，而 &lt;code&gt;WalkNodes&lt;&#x2F;code&gt; 拥有指针接收者，那么调用时会隐式获取 &lt;code&gt;chunkstore&lt;&#x2F;code&gt; 的地址，而这个地址指向我们新复制的结构体中的内容。但仔细观察，这里并非如此，因为 &lt;code&gt;chunkstore&lt;&#x2F;code&gt; 是一个接口。在 Go 语言中，接口值本质上是一个智能指针。因此，传递给 &lt;code&gt;WalkNodes&lt;&#x2F;code&gt; 函数的值，要么是实现该接口的值的指针，要么是该值的副本。在这两种情况下，接收者都不会指向 &lt;code&gt;vs&lt;&#x2F;code&gt;。&lt;code&gt;vs&lt;&#x2F;code&gt; 不会逃逸（&lt;code&gt;escape&lt;&#x2F;code&gt;）。它不会存活超过对 &lt;code&gt;GetBytes&lt;&#x2F;code&gt; 的调用，因此也不需要被存储在堆上。&lt;&#x2F;p&gt;
&lt;p&gt;但是编译器为什么还是将它存储在堆上呢？&lt;&#x2F;p&gt;
&lt;p&gt;之前我说过当编译器“推断出指向 &lt;code&gt;x&lt;&#x2F;code&gt; 的指针将存在时间超过函数调用”时，会将局部变量分配到堆上。但更准确的说法是，编译器在“无法推断出指向 x 的指针不会超出函数调用时间”时，才选择堆分配。这是因为如果编译器无法确定是否发生逃逸，它必须谨慎处理，假设会发生逃逸。堆分配虽然较慢，但总是安全的。&lt;&#x2F;p&gt;
&lt;p&gt;编译器试图证明一个变量不会超过当前栈活跃时间的过程称为逃逸分析。&lt;&#x2F;p&gt;
&lt;p&gt;【官方文档中详细讲解了编译器的逃逸分析，这里给出链接】(https:&#x2F;&#x2F;go.dev&#x2F;doc&#x2F;faq#stack_or_heap) 引用如下：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;在当前的编译器中，如果一个变量被取址，该变量就有可能被分配到堆上。但是，基本的逃逸分析可以识别出某些情况下，这些变量不会在函数返回后继续存活，因此可以将它们分配在栈上。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;重点是我的：这是一个基本的逃逸分析。因此，尽管我们知道方法执行完毕后，对被复制的接收者不会有任何引用，但逃逸分析可能不够复杂，无法检测出这一点。&lt;&#x2F;p&gt;
&lt;p&gt;语言确实给了我们一点小提示：虽然我们无法控制一个值会被分配到哪里，但可以通过运行 &lt;code&gt;go build -gcflags &quot;-m&quot;&lt;&#x2F;code&gt; 命令，让编译器告诉我们该值被分配到了哪里以及原因。&lt;&#x2F;p&gt;
&lt;p&gt;当我带着这个额外的参数编译 Dolt 时，我在输出中发现了以下内容：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;store&#x2F;prolly&#x2F;tree&#x2F;node_store.go:93:7:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; parameter ns leaks to &lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;heap&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-end z-shell&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; with derefs=1:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;store&#x2F;prolly&#x2F;tree&#x2F;node_store.go:93:7:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;   flow: &lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;heap&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-end z-shell&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; = &lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;*&lt;&#x2F;span&gt;ns:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;store&#x2F;prolly&#x2F;tree&#x2F;node_store.go:93:7:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;     from ns.chunkStore (dot of pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;at&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; store&#x2F;prolly&#x2F;tree&#x2F;node_store.go:99:14&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;store&#x2F;prolly&#x2F;tree&#x2F;node_store.go:93:7:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;     from ns.chunkStore.WalkNodes(ctx, ref&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-punctuation z-definition z-compound z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;call&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; parameter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; at store&#x2F;prolly&#x2F;tree&#x2F;node_store.go:99:24&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;store&#x2F;prolly&#x2F;tree&#x2F;node_store.go:93:7:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; leaking param content: ns&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;编译器看到 &lt;code&gt;ns.chunkStore&lt;&#x2F;code&gt; 被作为参数传递给某个函数，认为该值会发生逃逸。因此，编译器无法确定接收者是否可以安全地存储在栈上。&lt;&#x2F;p&gt;
&lt;p&gt;这可能是编译器的一个 bug。也有可能存在一些边缘情况，通过该方法调用引用确实可以逃逸，而编译器没有足够的上下文来排除这种可能性。编译器很复杂，我可以理解它可能做出任何一种判断。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-takeaway&quot;&gt;The Takeaway&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-takeaway&quot; aria-label=&quot;Anchor link for: the-takeaway&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;解决方法很简单：使用指针接收者而不是值接收者，避免不必要的复制。但是，探究这次回归的原因却揭示了令人惊讶的复杂行为。&lt;&#x2F;p&gt;
&lt;p&gt;如果这次调查让我们有所收获，那就是：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;理解为什么编译器会在内存分配上做出决策对于编写高性能代码非常重要。像 &lt;code&gt;-gcflags &quot;-m&quot;&lt;&#x2F;code&gt; 这样的工具能够提供对编译器决策的深入见解，对于理解和优化性能非常有帮助。&lt;&#x2F;li&gt;
&lt;li&gt;在有垃圾回收的语言中，将值存储在堆上始终是安全的，但这会带来性能开销：不仅在最初分配时有成本，垃圾回收时也会产生开销。由于堆分配总是安全的，除非能够证明栈分配也是安全的，否则 Golang 会优先选择堆分配。&lt;&#x2F;li&gt;
&lt;li&gt;推荐使用指针接收者，以避免不必要的复制，因为这些复制很容易导致额外的堆分配。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.dolthub.com&#x2F;blog&#x2F;2025-04-18-optimizing-heap-allocations&#x2F;&quot;&gt;https:&#x2F;&#x2F;www.dolthub.com&#x2F;blog&#x2F;2025-04-18-optimizing-heap-allocations&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;tonybai.com&#x2F;2025&#x2F;04&#x2F;25&#x2F;hidden-costs-of-go-value-receiver&#x2F;&quot;&gt;https:&#x2F;&#x2F;tonybai.com&#x2F;2025&#x2F;04&#x2F;25&#x2F;hidden-costs-of-go-value-receiver&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Windows | Docker容器的端口无法正常工作</title>
          <pubDate>Fri, 25 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-25-windows-docker-dynamicport/</link>
          <guid>https://inasa.dev/posts/25-04-25-windows-docker-dynamicport/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-25-windows-docker-dynamicport/">&lt;h2 id=&quot;wen-ti&quot;&gt;问题&lt;a class=&quot;zola-anchor&quot; href=&quot;#wen-ti&quot; aria-label=&quot;Anchor link for: wen-ti&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;docker&lt;&#x2F;code&gt;容器监听报错&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;Error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; response from daemon: Ports are not available: exposing port TCP 0.0.0.0:4308 -&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-file-descriptor z-shell&quot;&gt;0&lt;&#x2F;span&gt;.0.0.0:0: listen tcp 0.0.0.0:4308: bind: An attempt was made to access a socket in a way forbidden by its access permissions.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;使用&lt;code&gt;netstat -ano&lt;&#x2F;code&gt;也没有其他服务占用端口&lt;&#x2F;p&gt;
&lt;h2 id=&quot;jie-jue&quot;&gt;解决&lt;a class=&quot;zola-anchor&quot; href=&quot;#jie-jue&quot; aria-label=&quot;Anchor link for: jie-jue&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;通过&lt;code&gt;netsh interface ipv4 show excludedportrange protocol=tcp&lt;&#x2F;code&gt;发现，需要监听的端口被包含在里面。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;4084-4133&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;4134-4233&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;4234-4333&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;4306-4456&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;4709-4808&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;4809-4908&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;4909-5008&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;5041-5140&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;5357-5357&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;50000-50059&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;使用&lt;code&gt;netsh int ipv4 show dynamicport tcp&lt;&#x2F;code&gt;发现保留端口号是从&lt;code&gt;1024&lt;&#x2F;code&gt;开始的。&lt;&#x2F;p&gt;
&lt;p&gt;根本原因归结于 &lt;code&gt;Windows&lt;&#x2F;code&gt; 的“TCP 动态端口范围”，并且可能由于 &lt;code&gt;Hyper-V&lt;&#x2F;code&gt; 预留的端口号导致冲突。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;solution-1&quot;&gt;solution 1&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution-1&quot; aria-label=&quot;Anchor link for: solution-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;在原有保留端口中排除特定端口&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;禁用 Hyper-V（这将需要重启几次）&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dism.exe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;Online &#x2F;Disable-Feature:Microsoft-Hyper-V&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;完成所有必要的重启后，预留你需要的端口，以防 Hyper-V 重新占用该端口。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;netsh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; int ipv4 add excludedportrange protocol=tcp startport=&lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;your port&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-end z-shell&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; numberofports=1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;重新启用 Hyper-V（这将需要重启几次）&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;dism.exe&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;Online &#x2F;Enable-Feature:Microsoft-Hyper-V &#x2F;All&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;solution-2&quot;&gt;solution 2&lt;a class=&quot;zola-anchor&quot; href=&quot;#solution-2&quot; aria-label=&quot;Anchor link for: solution-2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;重置“TCP 动态端口范围”，使 &lt;code&gt;Hyper-V&lt;&#x2F;code&gt; 只预留我们设置的端口范围&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;netsh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; int ipv4 set dynamic tcp start=49152 num=16384&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;netsh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; int ipv6 set dynamic tcp start=49152 num=16384&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;docker&#x2F;for-win&#x2F;issues&#x2F;3171&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;docker&#x2F;for-win&#x2F;issues&#x2F;3171&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;zhaoji.wang&#x2F;solve-the-problem-of-windows-10-ports-being-randomly-reserved-occupied-by-hyper-v&#x2F;&quot;&gt;https:&#x2F;&#x2F;zhaoji.wang&#x2F;solve-the-problem-of-windows-10-ports-being-randomly-reserved-occupied-by-hyper-v&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | 什么是Event Sourcing？</title>
          <pubDate>Wed, 23 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-23-what-is-event-sourcing/</link>
          <guid>https://inasa.dev/posts/25-04-23-what-is-event-sourcing/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-23-what-is-event-sourcing/">&lt;h2 id=&quot;event-sourcing&quot;&gt;Event Sourcing&lt;a class=&quot;zola-anchor&quot; href=&quot;#event-sourcing&quot; aria-label=&quot;Anchor link for: event-sourcing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;传统的数据存储通常关注实体的当前状态。例如，在电子商务系统中，你可能会存储客户订单的当前状态：商品、数量、收货地址等。而事件溯源采用了不同的方法。它不是直接存储当前状态，而是存储导致该状态的事件。每个事件都代表了过去发生的一个事实。可以把它看作银行对账单中详细的交易日志。这些事件是不可变的，存储在仅追加的事件存储中。核心思想是应用程序的状态可以通过按事件发生的顺序重放这些事件来推导，就像你可以通过从头重放所有交易来得到当前的银行余额一样。这使得事件溯源对于需要高度可审计性和可追踪性的应用特别有用。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F825b2776-19f8-48d5-b906-df6d10ad2c54_2598x1601.png&quot; alt=&quot;Fig. Event Sourcing&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-event-sourcing-works&quot;&gt;How Event Sourcing Works&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-event-sourcing-works&quot; aria-label=&quot;Anchor link for: how-event-sourcing-works&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;在事件溯源系统中，应用状态的每一次变化都会被捕捉为一个事件对象。这些事件随后被存储在事件存储中，事件存储是一种为处理事件数据而优化的数据库。以下是事件溯源的分步骤工作原理：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;事件创建：当用户执行某个操作（例如，下订单）时，应用会创建一个描述该操作的事件对象。&lt;&#x2F;li&gt;
&lt;li&gt;事件存储：该事件被存储在事件存储中。该存储是仅追加的，意味着事件只能被添加，永远不会被修改或删除。&lt;&#x2F;li&gt;
&lt;li&gt;状态重建：为了确定实体（例如，一个订单）的当前状态，应用会从事件存储中重放所有与该实体相关的事件。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;想象一个电子商务应用。与其存储购物车的当前状态（商品、数量等），我们存储像“ItemAddedToCart”（商品加入购物车）、“ItemRemovedFromCart”（商品从购物车移除）、“QuantityUpdated”（数量更新）等事件。每个事件代表购物车的一个具体变化。购物车的当前状态可以通过按顺序重放这些事件随时重建。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;rebuilding-state-in-event-sourcing&quot;&gt;Rebuilding State in Event Sourcing&lt;a class=&quot;zola-anchor&quot; href=&quot;#rebuilding-state-in-event-sourcing&quot; aria-label=&quot;Anchor link for: rebuilding-state-in-event-sourcing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;从事件中重建状态涉及从事件存储中读取与某个实体相关的所有事件，并按顺序应用这些事件以重建当前状态。这就像模拟所有发生过的变化来构建当前状态。例如，考虑一个电子商务应用，其中订单经历了“已创建”、“已付款”和“已发货”等不同状态。为了确定订单的当前状态，你需要：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;从事件存储中检索与订单相关的所有事件。&lt;&#x2F;li&gt;
&lt;li&gt;初始化一个空的订单对象。&lt;&#x2F;li&gt;
&lt;li&gt;按存储的顺序将每个事件应用到订单对象上。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;经过这个过程后，订单对象将反映订单的当前状态。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bf36752-8f52-4182-a20b-9e64a3e56565_2095x2279.png&quot; alt=&quot;Fig. Rebuilding final state from events&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-of-snapshots-in-rebuilding-state&quot;&gt;Use of Snapshots in Rebuilding State&lt;a class=&quot;zola-anchor&quot; href=&quot;#use-of-snapshots-in-rebuilding-state&quot; aria-label=&quot;Anchor link for: use-of-snapshots-in-rebuilding-state&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;随着事件数量的增加，重放整个事件流以重建状态可能会变得缓慢且低效。这时，快照就派上用场了。快照是实体在特定时间点的保存状态。应用程序不必从头重放所有事件，而是可以加载最新的快照，然后只重放快照之后发生的事件。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb46fe5e6-0972-46ad-8648-38689de661b1_2112x1663.png&quot; alt=&quot;Fig. Rebuilding Final State From Snapshot and Events&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pros-and-cons&quot;&gt;Pros and Cons&lt;a class=&quot;zola-anchor&quot; href=&quot;#pros-and-cons&quot; aria-label=&quot;Anchor link for: pros-and-cons&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;优点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;可审计性：事件溯源提供了完整的变更历史，使得审计和追踪实体状态随时间变化变得容易。&lt;&#x2F;li&gt;
&lt;li&gt;调试：重放事件的能力使得通过重现实体在任意时间点的精确状态来调试问题变得更加简单。&lt;&#x2F;li&gt;
&lt;li&gt;灵活性：由于状态是从事件派生的，因此可以轻松添加新功能，或在不影响历史数据的情况下更改现有功能。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;缺点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;复杂性：事件溯源增加了应用的复杂性。你必须围绕事件设计系统，实现状态重建，并管理快照。&lt;&#x2F;li&gt;
&lt;li&gt;存储需求：存储所有事件可能导致大量存储需求，尤其是对于运行时间长且事件众多的系统。&lt;&#x2F;li&gt;
&lt;li&gt;数据隐私：存储所有事件可能引发隐私问题，因为历史数据可能包含必须谨慎管理的敏感信息。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;newsletter.scalablethread.com&#x2F;p&#x2F;what-is-event-sourcing&quot;&gt;https:&#x2F;&#x2F;newsletter.scalablethread.com&#x2F;p&#x2F;what-is-event-sourcing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | 分布式系统中的 Saga 模式是什么？</title>
          <pubDate>Wed, 23 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-23-what-is-saga-pattern-in-distributed-systems/</link>
          <guid>https://inasa.dev/posts/25-04-23-what-is-saga-pattern-in-distributed-systems/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-23-what-is-saga-pattern-in-distributed-systems/">&lt;p&gt;在分布式系统中，微服务为构建可扩展且有弹性的应用程序提供了方法。这些应用程序通常需要多个服务之间的通信来处理单个请求。例如，一个单一请求，如订购产品，可能涉及多个步骤和服务：库存、支付、运输等。这种分布式特性使得确保数据一致性和原子性成为一个复杂的挑战，尤其是当每个服务拥有自己的数据库并独立运行时。如何保证当支付服务成功时，库存得到更新，运输过程启动，同时保持数据完整性？传统的 ACID 事务设计用于具有单一数据库的单体应用程序，在跨多个服务时表现不佳。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-the-saga-pattern&quot;&gt;What is the Saga Pattern?&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-is-the-saga-pattern&quot; aria-label=&quot;Anchor link for: what-is-the-saga-pattern&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Saga 模式是一种设计模式，通过将多个服务之间的事务更新拆分为一系列小的本地事务更新，称为“saga 步骤”或“子事务”，来帮助管理这些事务更新。每个步骤代表与单个服务交互的工作单元。一旦一个步骤完成，它将触发序列中的下一个步骤。如果任何步骤失败，saga 会执行补偿性更新，以撤销前面步骤所做的更改，确保系统返回到其初始状态。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c90ec68-13fb-428a-a0f1-6d76ee34749a_3245x1346.png&quot; alt=&quot;Fig. Saga Pattern&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;types-of-saga-approaches&quot;&gt;Types of Saga Approaches&lt;a class=&quot;zola-anchor&quot; href=&quot;#types-of-saga-approaches&quot; aria-label=&quot;Anchor link for: types-of-saga-approaches&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;实现 Saga 模式主要有两种方法：编排（Orchestration）和编舞（Choreography）。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;orchestration&quot;&gt;Orchestration&lt;a class=&quot;zola-anchor&quot; href=&quot;#orchestration&quot; aria-label=&quot;Anchor link for: orchestration&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;在这种方法中，由一个中央编排服务负责协调 saga 步骤。编排者告诉每个服务何时执行其本地事务。它维护 saga 的状态，并通过调用补偿事务来处理任何失败。编排者了解整个 saga 流程。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-it-works&quot;&gt;How it works&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-it-works&quot; aria-label=&quot;Anchor link for: how-it-works&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;客户端通过与编排者通信来启动 saga。然后，编排者调用第一个服务。成功完成后，编排者进入下一步骤，调用相应的服务。如果某个服务失败，编排者会按相反顺序触发补偿事务。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3952805-6a2d-447e-801a-948121d0471b_3083x2312.png&quot; alt=&quot;Fig. Orchestration Approach&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;choreography&quot;&gt;Choreography&lt;a class=&quot;zola-anchor&quot; href=&quot;#choreography&quot; aria-label=&quot;Anchor link for: choreography&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;在编舞方法中，没有中央协调者。相反，参与 saga 的每个服务都知道自己的角色，并通过事件或消息与其他服务进行通信。每个服务监听特定事件，并在收到相应事件时执行本地事务。saga 流程分布在各个服务之间。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;how-it-works-1&quot;&gt;How it works&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-it-works-1&quot; aria-label=&quot;Anchor link for: how-it-works-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;客户端通过与第一个服务通信来启动 saga。该服务执行其事务并发布一个事件。其他监听此事件的服务执行各自的事务并发布它们的事件。这个连锁反应持续进行，直到 saga 完成。如果某个服务失败，它会发布一个补偿事件，触发其他服务执行补偿事务。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8182ff0f-31e8-4434-bc15-b0f363afc914_3649x2021.png&quot; alt=&quot;Fig. Choreography Approach&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;orchestration-v-s-choreography&quot;&gt;Orchestration v&#x2F;s Choreography&lt;a class=&quot;zola-anchor&quot; href=&quot;#orchestration-v-s-choreography&quot; aria-label=&quot;Anchor link for: orchestration-v-s-choreography&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;编舞没有单点故障，因为每个服务都管理自己在 saga 中的部分。&lt;&#x2F;li&gt;
&lt;li&gt;编排通过集中控制提供了简化的错误处理和监控。相比之下，在编舞中，每个服务需要处理自己的错误，这可能导致复杂的错误处理逻辑。&lt;&#x2F;li&gt;
&lt;li&gt;在编排中，协调者需要了解 saga 中所有相关的服务，这可能导致紧耦合。相比之下，在编舞中，服务需要就事件和事务的顺序达成一致，这可能导致协调上的开销。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;pros-and-cons-of-saga-pattern&quot;&gt;Pros and Cons of Saga Pattern&lt;a class=&quot;zola-anchor&quot; href=&quot;#pros-and-cons-of-saga-pattern&quot; aria-label=&quot;Anchor link for: pros-and-cons-of-saga-pattern&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;优点:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;数据一致性：Saga 模式确保多个服务之间的数据一致性，即使在出现故障时也是如此。&lt;&#x2F;li&gt;
&lt;li&gt;可扩展性：它允许可扩展且低耦合的服务，因为每个服务可以独立运行。&lt;&#x2F;li&gt;
&lt;li&gt;灵活性：Saga 模式可以处理涉及多个服务和步骤的复杂业务事务。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;缺点:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;复杂性：实现 Saga 模式可能比较复杂，尤其是对于包含许多服务的大型系统。&lt;&#x2F;li&gt;
&lt;li&gt;错误处理：管理错误和补偿事务可能具有挑战性，特别是在编舞方法中。&lt;&#x2F;li&gt;
&lt;li&gt;性能开销：需要跟踪 saga 的状态并处理补偿事务，这可能会带来性能开销。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;newsletter.scalablethread.com&#x2F;p&#x2F;what-is-saga-pattern-in-distributed&quot;&gt;https:&#x2F;&#x2F;newsletter.scalablethread.com&#x2F;p&#x2F;what-is-saga-pattern-in-distributed&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | 事件驱动系统中的声明检查模式是什么？</title>
          <pubDate>Wed, 23 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-23-what-is-the-claim-check-pattern-in-event-driven-systems/</link>
          <guid>https://inasa.dev/posts/25-04-23-what-is-the-claim-check-pattern-in-event-driven-systems/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-23-what-is-the-claim-check-pattern-in-event-driven-systems/">&lt;p&gt;在分布式系统中，服务之间的通信通常依赖于消息传递。消息在各组件之间发送，以触发操作、共享数据或同步状态。然而，随着系统复杂度的增加，这些消息的大小可能成为一个重大挑战。直接传输包含大量负载的消息可能会使消息代理不堪重负，消耗过多带宽，并减慢处理速度。此外，一些消息代理对消息大小有限制，使得不可能直接发送大负载的消息。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-the-claim-check-pattern&quot;&gt;What is the Claim-Check Pattern?&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-is-the-claim-check-pattern&quot; aria-label=&quot;Anchor link for: what-is-the-claim-check-pattern&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;声明检查模式是一种消息设计模式，它将大数据负载的传输与实际消息分离开来。该模式不是将整个负载包含在消息中发送，而是将负载存储在外部存储系统中（例如，数据库、对象存储或文件系统），并只在消息中发送对存储数据的引用。这个引用通常被称为“声明检查”，类似于你在寄存衣物时收到的票据。该过程通过多步骤实现：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fee38bb12-c213-42b0-90f0-bb8acf8210c0_2770x1613.png&quot; alt=&quot;Fig. The Claim-Check Pattern&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;存储负载：当服务需要发送大消息时，首先将负载上传到外部存储系统。这可以是像Amazon S3、Azure Blob存储这样的云存储服务，或者分布式文件系统。&lt;&#x2F;li&gt;
&lt;li&gt;生成引用：一旦负载被存储，服务或数据库会生成一个唯一的引用（例如 URL、文件路径或数据库键），指向存储的数据。&lt;&#x2F;li&gt;
&lt;li&gt;发送声明检查：发送方服务不会发送整个负载，而是发送一个轻量级消息，消息中只包含引用（声明检查）及任何必要的元数据。&lt;&#x2F;li&gt;
&lt;li&gt;获取负载：接收服务使用声明检查从外部存储系统获取负载，当需要时进行取回。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;claim-check-with-event-sourcing-for-privacy&quot;&gt;Claim-Check with Event Sourcing for Privacy&lt;a class=&quot;zola-anchor&quot; href=&quot;#claim-check-with-event-sourcing-for-privacy&quot; aria-label=&quot;Anchor link for: claim-check-with-event-sourcing-for-privacy&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;事件溯源（Event Sourcing）是一种模式，其中应用程序的状态由一系列事件决定。然而，直接在事件中存储所有信息可能在处理敏感数据时引发隐私问题。声明检查（Claim-Check）通过确保敏感数据不直接存储在事件流中，从而在事件溯源中提升了隐私保护。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd9eb99d7-14d7-4944-81a8-a508ff2d3f6e_2203x2647.png&quot; alt=&quot;Fig. The Claim Check Pattern with Event Sourcing&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;分开存储敏感数据：不要将敏感数据（例如个人身份信息或 PII）直接嵌入事件中，而是存储在安全的外部存储系统中。&lt;&#x2F;li&gt;
&lt;li&gt;为敏感数据生成声明检查：在事件日志中仅包含声明检查（引用）。这确保敏感数据不会暴露在事件流中。&lt;&#x2F;li&gt;
&lt;li&gt;负载检索的访问控制：对外部存储系统实施严格访问控制，确保只有授权的服务或用户可以检索敏感数据。&lt;&#x2F;li&gt;
&lt;li&gt;审计追踪：事件溯源天然提供事件的审计追踪。结合存储位置的访问日志，可以维护完整的数据访问审计记录。&lt;&#x2F;li&gt;
&lt;li&gt;数据保留策略：对外部存储系统应用数据保留策略，在指定期限后自动删除或匿名化敏感数据，确保符合 GDPR 等隐私法规。&lt;&#x2F;li&gt;
&lt;li&gt;数据加密：敏感数据在存储前可以加密，提供额外的安全层。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;pros-and-cons&quot;&gt;Pros and Cons&lt;a class=&quot;zola-anchor&quot; href=&quot;#pros-and-cons&quot; aria-label=&quot;Anchor link for: pros-and-cons&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;优点:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;减少消息大小：通过将大负载存储在外部，消息变得轻量，提升性能并减少带宽使用。&lt;&#x2F;li&gt;
&lt;li&gt;增强安全性：敏感数据可以单独存储，并通过受控授权访问。数据和元数据可以应用不同的保留策略。&lt;&#x2F;li&gt;
&lt;li&gt;提高可扩展性：较小的消息减少了消息代理的负载，使系统能够处理更高的消息量。&lt;&#x2F;li&gt;
&lt;li&gt;成本效益：将大负载存储在成本效益高的存储系统（例如对象存储）中，通常比通过消息代理传输更便宜。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;缺点:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;复杂性增加：该模式引入了额外的组件（例如外部存储）和步骤（例如上传和检索负载），这可能使系统变得复杂。&lt;&#x2F;li&gt;
&lt;li&gt;延迟开销：从外部存储获取负载会增加延迟，这在低延迟系统中可能无法接受。&lt;&#x2F;li&gt;
&lt;li&gt;依赖外部存储：系统依赖于外部存储系统的可用性和性能。如果存储系统不可用，消息将无法被完全处理。&lt;&#x2F;li&gt;
&lt;li&gt;孤立数据的风险：如果声明检查丢失或未被处理，存储的数据可能变成孤立数据，占用存储空间但无实际用途。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;newsletter.scalablethread.com&#x2F;p&#x2F;what-is-the-claim-check-pattern-in&quot;&gt;https:&#x2F;&#x2F;newsletter.scalablethread.com&#x2F;p&#x2F;what-is-the-claim-check-pattern-in&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | 数据库如何通过预写日志（Write-Ahead Logs）避免数据丢失？</title>
          <pubDate>Tue, 22 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-22-how-databases-avoid-data-loss-with-write-ahead-logs/</link>
          <guid>https://inasa.dev/posts/25-04-22-how-databases-avoid-data-loss-with-write-ahead-logs/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-22-how-databases-avoid-data-loss-with-write-ahead-logs/">&lt;p&gt;故障是系统设计无论多么完善都必然会发生的一个属性，数据库也不例外！数据库在崩溃或故障后重启时，应该能够恢复到崩溃前的状态。除了故障处理之外，拥有多个副本的分布式数据库必须保持高性能和低延迟。这通过一种称为预写日志（Write-Ahead Logs，简称 WAL）的技术来实现。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-are-write-ahead-logs&quot;&gt;What are Write-Ahead Logs?&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-are-write-ahead-logs&quot; aria-label=&quot;Anchor link for: what-are-write-ahead-logs&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;数据库系统中的每个节点都会在持久存储中维护一个只追加的日志文件，客户端发送到该节点的每个更新操作首先被追加（写前日志）到该文件中，随后再应用到数据库中的数据。这种日志技术被称为写前日志（Write-Ahead Logging），因为更新命令是在&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;newsletter.scalablethread.com&#x2F;i&#x2F;145809328&#x2F;step-prepare&quot;&gt;对数据实际进行更新之前先写入日志的&lt;&#x2F;a&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0c5dda53-7a3f-4dbb-aae6-1de27f2166af_768x488.png&quot; alt=&quot;Fig. Every database node keeps its own Write-Ahead Log&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;预写日志（WAL）并不保存数据库中实际的数据状态，而是将每条日志记录作为客户端发送给数据库的查询或命令的副本。一旦查询被写入日志文件，就会在数据库中存储的数据上执行该查询。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c24c962-e48d-4cfc-91a6-1922797b128b_764x575.png&quot; alt=&quot;Fig. Each client command is APPENDED to the WAL&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-does-wal-help-prevent-data-loss&quot;&gt;How does WAL Help Prevent Data Loss?&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-does-wal-help-prevent-data-loss&quot; aria-label=&quot;Anchor link for: how-does-wal-help-prevent-data-loss&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;预写日志被写入持久存储（如磁盘），使其能够在节点故障后仍然存活。在分布式数据库中，一旦跟随节点在故障后重启，它会从头开始读取其预写日志文件，并依次执行日志文件中的更新操作。这样该节点就能恢复到故障发生前的状态。可以把它想象成银行对账单列出了所有的借记和贷记交易，如果这些交易逐一作用于初始余额，就能计算出账户的最终余额。&lt;&#x2F;p&gt;
&lt;p&gt;一旦跟随节点重建了数据状态，它会通过请求在该节点处于故障状态期间发生的所有客户端更新，将其预写日志（WAL）与主节点的 WAL 进行同步。在主节点共享了所有客户端更新后，跟随节点会更新自己的 WAL，并对数据执行所有的更新操作，以使数据状态与主节点及其他跟随节点保持一致。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb3b95071-4a28-4bf7-b41d-a5c007e1ad60_1146x1881.png&quot; alt=&quot;Fig. Crashed node reconstructs its prior state by executing commands from WAL&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;可能会出现预写日志（WAL）中有数百万条记录的情况，这会影响节点的重启时间。为了解决这个问题，数据库会定期对数据进行快照。在故障后重启时，只执行自上次快照以来追加的 WAL 记录。这大大减少了需要执行的 WAL 记录数量，从而提高了数据库状态重建的效率和性能。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;newsletter.scalablethread.com&#x2F;p&#x2F;how-databases-avoid-data-loss-with&quot;&gt;https:&#x2F;&#x2F;newsletter.scalablethread.com&#x2F;p&#x2F;how-databases-avoid-data-loss-with&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | NoSQL数据库如何加速写密集型工作负载？</title>
          <pubDate>Tue, 22 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-22-how-nosql-databases-speed-up-write-heavy-workloads/</link>
          <guid>https://inasa.dev/posts/25-04-22-how-nosql-databases-speed-up-write-heavy-workloads/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-22-how-nosql-databases-speed-up-write-heavy-workloads/">&lt;h2 id=&quot;understanding-the-problem&quot;&gt;Understanding the Problem&lt;a class=&quot;zola-anchor&quot; href=&quot;#understanding-the-problem&quot; aria-label=&quot;Anchor link for: understanding-the-problem&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;在依赖B树的数据库（例如MySQL、PostgreSQL等）中，写入数据需要找到适当的树节点（或多个节点）来添加新数据，先从磁盘中读取该节点，进行更新操作，然后再将节点写回磁盘。在某些情况下，树结构可能还需要重新平衡（比如新节点被创建时）。换句话说，为了写入几字节的数据，需要从磁盘上随机位置读取一个或多个几个千字节大小的树节点，更新它们，再写回磁盘。这样的随机磁盘I&#x2F;O（这会增加延迟）以及高读写比例（读取数据大小与写入新数据大小之比）都会影响整体的写入性能。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01e93dce-3d62-457c-8c90-201d195bfdd3_3017x1367.png&quot; alt=&quot;Fig. Adding or updating data in databases that use B-Tree&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-a-log-structured-merge-lsm-tree&quot;&gt;What is a Log Structured Merge (LSM) Tree?&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-is-a-log-structured-merge-lsm-tree&quot; aria-label=&quot;Anchor link for: what-is-a-log-structured-merge-lsm-tree&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;LSM树是一种优化数据库（如Cassandra、YugabyteDB等）写入性能的数据结构，通过在内存中缓冲写入操作，并定期将这些写入批量刷新到磁盘。由于这些写入是顺序地刷新到磁盘的（顺序磁盘I&#x2F;O的延迟低于随机磁盘I&#x2F;O），因此提升了写入效率。LSM树通过两个主要组件来实现这一点：&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-memtable&quot;&gt;1) Memtable&lt;a class=&quot;zola-anchor&quot; href=&quot;#1-memtable&quot; aria-label=&quot;Anchor link for: 1-memtable&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Memtable是一种内存中的数据结构（类似AVL树），用于按键排序保存键值对数据。相比B树将数据保存在磁盘上（随机磁盘I&#x2F;O）并保持排序，内存中的memtable数据保持排序更快。这使得对有序memtable的读写操作速度更快。所有写入操作先写入内存中有序的memtable，当memtable满了之后，才将其刷新到磁盘。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-sorted-string-tables-sstables&quot;&gt;2) Sorted String Tables (SSTables)&lt;a class=&quot;zola-anchor&quot; href=&quot;#2-sorted-string-tables-sstables&quot; aria-label=&quot;Anchor link for: 2-sorted-string-tables-sstables&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;一旦memtable满了，它会被刷新到磁盘上以追加方式存储的有序字符串表（SSTables）文件中（不允许更新）。SSTables中的数据是按键排序的，对于同一个键，文件中后出现的值比前面出现的值更新。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12a72234-2704-4555-927a-f485fdefa4ed_3714x1857.png&quot; alt=&quot;Fig. Memtable and SSTables in an LSM Tree&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;understanding-compaction-in-sstables&quot;&gt;Understanding Compaction in SSTables&lt;a class=&quot;zola-anchor&quot; href=&quot;#understanding-compaction-in-sstables&quot; aria-label=&quot;Anchor link for: understanding-compaction-in-sstables&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;当memtable满了之后，它会被写入磁盘，作为按键排序的SSTable文件。多次memtable刷新会产生多个SSTable文件。随着时间推移，同一个键可能会出现在不同的SSTable文件中，因为数据库中的键可以在不同时间被更新为不同的值，而SSTables是追加写入的。这意味着相比之前的memtable刷新，最近一次的memtable刷新会包含给定键的当前值。&lt;&#x2F;p&gt;
&lt;p&gt;为了保持数据为最新的值，SSTables会不定期地运行合并与压缩（merge and compaction）过程，将多个SSTable文件合并成一个。该过程如下进行：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;从每个SSTable文件的顶部读取第一个条目，比较它们的键；&lt;&#x2F;li&gt;
&lt;li&gt;将键值对中键最小的那一对添加到新的SSTable文件中。如果所有文件中包含相同键但对应不同的值，则视为最近更新的文件中的键值对（因为它包含最新更新），其他的都被丢弃；&lt;&#x2F;li&gt;
&lt;li&gt;该过程重复进行，直到所有文件中的键值对都被移动到新的合并压缩后的文件中。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9820202-5c93-4ec7-8b87-a522e8b6f0b1_4388x2958.png&quot; alt=&quot;Fig. Merge and Compaction in SSTables&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;writes-in-lsm-trees&quot;&gt;Writes in LSM Trees&lt;a class=&quot;zola-anchor&quot; href=&quot;#writes-in-lsm-trees&quot; aria-label=&quot;Anchor link for: writes-in-lsm-trees&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;写入操作首先写入memtable（保持数据按键排序）；&lt;&#x2F;li&gt;
&lt;li&gt;一旦memtable满了，它被顺序地以有序且追加写入（sequentially）的方式写入磁盘，形成一个SSTable文件。由于memtable已经保持数据的排序，这不会影响性能。这使得LSM树能够支持高写入吞吐量；&lt;&#x2F;li&gt;
&lt;li&gt;在一定时间间隔内，不同的SSTable文件会被合并和压缩。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81a6a8d6-8aff-4766-b430-c0e1f0ce07fc_3763x2104.png&quot; alt=&quot;Fig. Writes in LSM Trees&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-happens-to-memtable-data-in-case-of-a-crash&quot;&gt;What Happens to Memtable Data in Case of a Crash?&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-happens-to-memtable-data-in-case-of-a-crash&quot; aria-label=&quot;Anchor link for: what-happens-to-memtable-data-in-case-of-a-crash&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;由于memtable是保存在内存中的，数据库崩溃可能导致这些数据丢失。为了解决这个问题，memtable中的数据也会写入预写日志（Write-Ahead Logs，WAL Logs）。如果发生崩溃，memtable可以通过WAL日志重建，一旦memtable被刷新到磁盘，其对应的WAL日志就会被丢弃。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4bb101a2-ac5c-403a-b4f6-99a38616d29f_3201x3061.png&quot; alt=&quot;Fig. Using WAL to avoid Memtable dataloss in case of a crash&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;reads-in-lsm-trees&quot;&gt;Reads in LSM Trees&lt;a class=&quot;zola-anchor&quot; href=&quot;#reads-in-lsm-trees&quot; aria-label=&quot;Anchor link for: reads-in-lsm-trees&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;要读取的键首先会在memtable中搜索。由于memtable在内存中，查找速度很快。&lt;&#x2F;li&gt;
&lt;li&gt;如果在memtable中找不到该键，则会在最近刷新到磁盘的SSTable文件中查找。如果仍然找不到，再到更老的SSTable文件中查找，依此类推。这是因为读取操作可能会在所有SSTable文件合并压缩为一个文件之前发生。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F920c81ac-4015-457e-b47d-6699ec7dd8e7_3201x3061.png&quot; alt=&quot;Fig. Reads in LSM Trees&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-are-reads-optimized&quot;&gt;How are Reads Optimized?&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-are-reads-optimized&quot; aria-label=&quot;Anchor link for: how-are-reads-optimized&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;扫描SSTable文件会影响读取性能。为了优化读取：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;常用布隆过滤器（Bloom Filters）来判断一个键是否存在于SSTable中；&lt;&#x2F;li&gt;
&lt;li&gt;在内存中为部分键创建了一个稀疏索引（sparse index）用于SSTable。该索引包含少量键及其在SSTable文件中的位置。任何键的读取首先会在该稀疏索引中查找，找到目标键之前和之后的键对应的位置。由于SSTable中的数据是有序的，目标键必定位于这两个位置之间。这样就加快了读取速度，因为只需扫描这两个位置之间的键即可找到目标键。这类似于在字典中查找一个单词，我们不需要逐字扫描整个字典，而是查找位于目标单词之前和之后的两个单词之间的列表。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d91137e-01aa-454d-a00b-782ce24373fd_3600x2687.png&quot; alt=&quot;Fig. Optimizing reads in LSM Tree using Sparse Index&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;newsletter.scalablethread.com&#x2F;p&#x2F;how-lsm-trees-optimize-write-heavy&quot;&gt;https:&#x2F;&#x2F;newsletter.scalablethread.com&#x2F;p&#x2F;how-lsm-trees-optimize-write-heavy&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;B-tree#B-tree_usage_in_databases&quot;&gt;Wikipedia contributors. (2024b, September 13). B-Tree. Wikipedia. &lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Kleppmann, M. (2017, Chapter 3). Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems. “O’Reilly Media, Inc.”&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.scylladb.com&#x2F;glossary&#x2F;log-structured-merge-tree&#x2F;&quot;&gt;Sadeghi, Y. (2024, February 7). What is a Log Structured Merge Tree? Definition &amp;amp; FAQs | ScyllaDB. ScyllaDB. &lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.yugabyte.com&#x2F;preview&#x2F;architecture&#x2F;docdb&#x2F;lsm-sst&#x2F;&quot;&gt;Log structured merge(LSM) tree and Sorted string table (SST). (2024, April 22). YugabyteDB Docs.&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | 如何应对突发流量激增或“惊群效应”？</title>
          <pubDate>Tue, 22 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-22-thundering-herd-problem/</link>
          <guid>https://inasa.dev/posts/25-04-22-thundering-herd-problem/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-22-thundering-herd-problem/">&lt;h2 id=&quot;what-is-the-thundering-herd-problem&quot;&gt;What is the Thundering Herd Problem?&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-is-the-thundering-herd-problem&quot; aria-label=&quot;Anchor link for: what-is-the-thundering-herd-problem&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;想象这样一种场景：某个事件导致你的一项或多项服务流量骤增，超出了它们的处理能力。这可能会导致一个或多个依赖服务（比如数据库）过载并变得无响应，最终引发服务故障（级联故障）。此类事件可能包括多个服务实例失败，所有流量被重定向到单个实例；一张病毒式传播的图片或视频获得大量观看；或者节日期间的线上促销活动导致数据库超载。这种由级联故障引起的服务不可用，因突发流量激增而发生的情况，称为“惊群效应”（Thundering Herd Problem）。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7a4d49ca-120c-43d8-a3d4-fc70cd8a3332_834x702.png&quot; alt=&quot;Thundering Herd Problem&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-to-handle-the-situation&quot;&gt;How to Handle the Situation?&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-to-handle-the-situation&quot; aria-label=&quot;Anchor link for: how-to-handle-the-situation&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;exponential-jitter-and-retry-zhi-shu-dou-dong-yu-zhong-shi&quot;&gt;Exponential Jitter and Retry(指数抖动与重试)&lt;a class=&quot;zola-anchor&quot; href=&quot;#exponential-jitter-and-retry-zhi-shu-dou-dong-yu-zhong-shi&quot; aria-label=&quot;Anchor link for: exponential-jitter-and-retry-zhi-shu-dou-dong-yu-zhong-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;当某个服务未能响应时，直觉上的解决方案是重试请求，假设这是一次短暂的故障。然而，这种方法可能导致惊群效应，或者加剧已有的惊群效应，因为所有客户端会同时重试，导致系统资源被压垮。相反，如果客户端在随机间隔时间内重试，过载的资源就有时间恢复并响应。这种重试时间的随机性称为“抖动”（Jitter），有助于更均匀地分配负载，防止系统遭受进一步的压力。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff928067b-5ad2-454a-ba59-c50827a126cd_927x792.png&quot; alt=&quot;Exponential Jitter and Retry&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“抖动”（Jitter）指的是在固定等待时间的基础上，随机加上或减去一段时间，使得每次重试的间隔时间不完全相同。&lt;&#x2F;p&gt;
&lt;p&gt;抖动（Jitter）本身并不能解决服务响应失败的根本原因，比如服务器过载、网络故障或者代码错误。不过，抖动的作用在于减轻由于大量客户端同步重试引起的额外压力，防止“惊群效应”恶化问题。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;当服务暂时过载时，如果所有客户端都在固定的时间点（比如3秒）同时重试，瞬间会产生大量请求涌入，导致服务压力骤增，更可能让服务继续失败。&lt;&#x2F;li&gt;
&lt;li&gt;通过抖动，让客户端的重试时间分散开来，服务得以“喘息”恢复部分处理能力，而不是被一波又一波同步请求压垮。&lt;&#x2F;li&gt;
&lt;li&gt;这样，虽然服务仍可能因负载大而失败，但它的恢复速度会更快，整体系统的稳定性和可用性更好。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;简单比喻就是：
如果一扇门很窄，很多人同时撞击会更容易把门撞坏；如果大家错开时间进门，门可以更平稳地应付人流，减少损坏。&lt;&#x2F;p&gt;
&lt;p&gt;所以，抖动是配合其他手段（如限流、降级、扩容等）来提升系统健壮性的一个重要策略，能有效避免雪上加霜。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;queueing-requests-pai-dui-qing-qiu&quot;&gt;Queueing Requests(排队请求)&lt;a class=&quot;zola-anchor&quot; href=&quot;#queueing-requests-pai-dui-qing-qiu&quot; aria-label=&quot;Anchor link for: queueing-requests-pai-dui-qing-qiu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;考虑这样一种情景：请求从缓存中获取某张图片时发生缓存未命中，导致请求被转发到源数据存储进行处理。如果大量同时请求都发生缓存未命中，并被转发到数据存储，就可能引发惊群效应。由于所有请求都是针对同一张图片，只有一个请求应该被转发到数据存储来完成处理。其他请求可以排队等待，并在初始请求从数据存储返回后，缓存被更新后，再从缓存中进行响应。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe064f974-cff3-4065-a697-eb0baeaa6bcf_880x871.png&quot; alt=&quot;Queueing Requests&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;load-balancing-fu-zai-jun-heng&quot;&gt;Load Balancing(负载均衡)&lt;a class=&quot;zola-anchor&quot; href=&quot;#load-balancing-fu-zai-jun-heng&quot; aria-label=&quot;Anchor link for: load-balancing-fu-zai-jun-heng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;每个大规模应用在某个阶段都需要在后端进行服务复制来应对不断增加的流量。然而，如果流量没有均匀分布到所有服务副本上，可能会导致某些实例负载过重。使用负载均衡器将负载均匀分配，有助于防止惊群效应的发生。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e3b85f2-0983-46e4-b869-088e098f7533_791x365.png&quot; alt=&quot;Load Balancing&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;rate-limiting-su-lu-xian-zhi&quot;&gt;Rate Limiting(速率限制)&lt;a class=&quot;zola-anchor&quot; href=&quot;#rate-limiting-su-lu-xian-zhi&quot; aria-label=&quot;Anchor link for: rate-limiting-su-lu-xian-zhi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;如果一个服务开放了API，给客户端提供无限制的访问权限，当一个或多个客户端滥用时，可能会造成灾难性后果。像DDOS攻击或定时批处理作业这类场景都可能引发惊群效应。通过实现速率限制来控制客户端调用API的频率，可以帮助管理高吞吐量的客户端，防止此类问题的发生。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf3e383a-c026-4ecf-9084-c7e3354cc84a_700x776.png&quot; alt=&quot;Rate Limiting&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;circuit-breaker-duan-lu-qi&quot;&gt;Circuit Breaker(断路器)&lt;a class=&quot;zola-anchor&quot; href=&quot;#circuit-breaker-duan-lu-qi&quot; aria-label=&quot;Anchor link for: circuit-breaker-duan-lu-qi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;服务依赖项（例如数据库）可能会因惊群效应而失败。类似于微型断路器（MCB）通过在电压突然升高时断开电路来保护电路，服务也可以实现断路器机制。这种方式会暂停向依赖项发送更多的请求，直到依赖恢复并准备好再次处理流量为止。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2c9a3560-7999-43d7-bef0-89e95370b6a7_786x708.png&quot; alt=&quot;Circuit Breaker&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;load-shedding-fu-zai-xie-zai&quot;&gt;Load Shedding(负载卸载)&lt;a class=&quot;zola-anchor&quot; href=&quot;#load-shedding-fu-zai-xie-zai&quot; aria-label=&quot;Anchor link for: load-shedding-fu-zai-xie-zai&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;虽然断路器允许服务停止向依赖项发送请求，但依赖项自身仍可以丢弃进入的请求，这种技术称为负载卸载，用以防止惊群效应。这类似于电力系统中的轮流停电，电力供应商通过降低负载来防止当需求超过容量时导致整个系统崩溃。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;substackcdn.com&#x2F;image&#x2F;fetch&#x2F;w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep&#x2F;https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52d97d7c-34cd-402a-9959-b4c6e7684e1b_793x705.png&quot; alt=&quot;Load Shedding&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;circuit-breakerhe-load-sheddingde-qu-bie&quot;&gt;Circuit Breaker和Load Shedding的区别&lt;a class=&quot;zola-anchor&quot; href=&quot;#circuit-breakerhe-load-sheddingde-qu-bie&quot; aria-label=&quot;Anchor link for: circuit-breakerhe-load-sheddingde-qu-bie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Circuit Breaker（断路器）：当检测到依赖服务不可用或负载过高时，断路器会“断开”请求通路，阻止服务继续向该依赖发送请求，但通常会快速返回一个失败响应，告知调用方请求未被处理。&lt;&#x2F;li&gt;
&lt;li&gt;Load Shedding（负载卸载）：依赖服务本身主动丢弃一部分请求，不予处理，不返回具体错误响应，目的是减轻自身压力，防止系统整体崩溃。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;简而言之，断路器是请求端主动停止发送请求，而负载卸载是依赖端主动丢弃请求。两者都是为防止系统过载，缓解“惊群效应”的重要手段，但侧重点和实现位置不同。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;newsletter.scalablethread.com&#x2F;p&#x2F;how-to-handle-sudden-bursts-of-traffic&quot;&gt;https:&#x2F;&#x2F;newsletter.scalablethread.com&#x2F;p&#x2F;how-to-handle-sudden-bursts-of-traffic&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | Zero Copy Readers in Go</title>
          <pubDate>Tue, 22 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-22-zero-copy-readers-in-go/</link>
          <guid>https://inasa.dev/posts/25-04-22-zero-copy-readers-in-go/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-22-zero-copy-readers-in-go/">&lt;p&gt;&lt;code&gt;io.Reader&lt;&#x2F;code&gt; 接口是一个小型接口，定义了一个单一的 &lt;code&gt;Read&lt;&#x2F;code&gt; 方法。调用者调用实现了 &lt;code&gt;Reader&lt;&#x2F;code&gt; 接口的类型时，会传入一个字节切片，底层的数据源会将字节填充到这个切片中。这个数据源可以是文件、网络套接字等。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Reader&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Read&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;p&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;不过，这个接口也带来了一些挑战。它要求必须将源数据复制到调用者提供的字节切片中。如果数据源已经存在于内存里，允许调用者直接从已经在内存中的数组读取数据会更高效，而不必做复制。在这篇文章中，我将介绍几个这类场景的示例。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;slices-and-arrays-in-go&quot;&gt;Slices and Arrays in Go&lt;a class=&quot;zola-anchor&quot; href=&quot;#slices-and-arrays-in-go&quot; aria-label=&quot;Anchor link for: slices-and-arrays-in-go&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;快速复习一下 &lt;code&gt;Go&lt;&#x2F;code&gt; 语言中的切片是很有用的。&lt;code&gt;Go&lt;&#x2F;code&gt; 官方博客中有一篇文章&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;go.dev&#x2F;blog&#x2F;slices-intro&quot;&gt;《Go Slices: usage and internals》&lt;&#x2F;a&gt;对切片的实现机制做了很好的介绍。&lt;&#x2F;p&gt;
&lt;p&gt;切片是由内存中的一个数组支持的，切片本身提供了一个对该数组子集的“视图”。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;a&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;4&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;7&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;9&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;s&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;6&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 3,4,5
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;cap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 7，表示从切片起始位置到数组末尾的容量
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;然而，切片会保留对完整的底层数组的引用，这意味着你可以创建切片来查看数据的子集，而不需要分配一个新的数组并复制数据。
需要注意的是，如果你修改了切片中的数据，原始数组也会被修改。&lt;&#x2F;p&gt;
&lt;p&gt;我们希望利用切片这一特性，能够在不做不必要复制的情况下直接读取数组的数据。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bytes-reader&quot;&gt;bytes.Reader&lt;a class=&quot;zola-anchor&quot; href=&quot;#bytes-reader&quot; aria-label=&quot;Anchor link for: bytes-reader&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;bytes.Reader&lt;&#x2F;code&gt; 是一个流行的类型，它实现了针对字节切片的 &lt;code&gt;io.Reader&lt;&#x2F;code&gt; 接口。不幸的是，直接使用这些方法并不能实现对底层 &lt;code&gt;[]byte&lt;&#x2F;code&gt; 的零拷贝读取。
相反，你需要用一种更间接的方式，使用 &lt;code&gt;WriteTo&lt;&#x2F;code&gt; 方法，&lt;code&gt;bytes.Reader&lt;&#x2F;code&gt; 会将底层 &lt;code&gt;[]byte&lt;&#x2F;code&gt; 的切片传递给给定的 &lt;code&gt;io.Writer&lt;&#x2F;code&gt;。
这样就可以在不进行数据复制的情况下读取底层的数据。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;zeroCopyWriter&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;w&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;zeroCopyWriter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Write&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;b&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;r&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;bytes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;NewReader&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Hello, 世界&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;WriteTo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;zeroCopyWriter&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;zeroCopyWriter&lt;&#x2F;code&gt; 是我们自定义的一个结构体，实现了 &lt;code&gt;io.Writer&lt;&#x2F;code&gt; 接口的 &lt;code&gt;Write&lt;&#x2F;code&gt; 方法。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;Write&lt;&#x2F;code&gt; 方法收到的参数 &lt;code&gt;b []byte&lt;&#x2F;code&gt; 是从 &lt;code&gt;bytes.Reader&lt;&#x2F;code&gt; 底层传递过来的字节切片，是底层&lt;code&gt;[]byte&lt;&#x2F;code&gt; 的一个切片引用（没做拷贝）。
调用 &lt;code&gt;r.WriteTo(&amp;amp;zeroCopyWriter{})&lt;&#x2F;code&gt;，实际上会触发 &lt;code&gt;bytes.Reader&lt;&#x2F;code&gt; 内部调用 &lt;code&gt;zeroCopyWriter.Write&lt;&#x2F;code&gt; 并传入它的底层 &lt;code&gt;[]byte&lt;&#x2F;code&gt;。
这样，我们可以“零拷贝”直接拿到底层数据，而不用调用 &lt;code&gt;r.Read()&lt;&#x2F;code&gt; 那样拷贝数据。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bufio-reader&quot;&gt;bufio.Reader&lt;a class=&quot;zola-anchor&quot; href=&quot;#bufio-reader&quot; aria-label=&quot;Anchor link for: bufio-reader&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;Go&lt;&#x2F;code&gt; 语言中的 &lt;code&gt;bufio.Reader&lt;&#x2F;code&gt; 是一个从底层 &lt;code&gt;io.Reader&lt;&#x2F;code&gt; 读取数据并将数据存储到缓冲区的类型。这使程序能够通过批量读取来减少系统调用次数，并允许调用者从存储的缓冲区中读取数据。&lt;&#x2F;p&gt;
&lt;p&gt;当调用 &lt;code&gt;bufio.Reader.Read&lt;&#x2F;code&gt; 时，如果读取器的缓冲区没有足够的字节，&lt;code&gt;bufio.Reader&lt;&#x2F;code&gt; 会调用底层的 &lt;code&gt;io.Reader&lt;&#x2F;code&gt; 来填充缓冲区，缓冲区默认大小是4096字节。通常这导致一个系统调用，从文件或网络套接字读取数据。然后字节会从缓冲区返回。一旦缓冲区被填满，之后的调用只要缓冲区数据足够，就可以直接从缓冲区读取。这非常有用，因为许多程序会频繁地进行小规模的读取调用，如果每次调用都产生系统调用，会影响性能。&lt;&#x2F;p&gt;
&lt;p&gt;第一次将数据复制进缓冲区是无法避免的，但我们可以避免第二次将数据从缓冲区复制到另一个数组。单独使用 &lt;code&gt;Read&lt;&#x2F;code&gt; 方法做不到这一点，但可以通过结合使用 &lt;code&gt;Buffered&lt;&#x2F;code&gt;、&lt;code&gt;Peek&lt;&#x2F;code&gt; 和 &lt;code&gt;Discard&lt;&#x2F;code&gt; 这些方法来实现。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;b&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Hello, 世界&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;r&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;bufio&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;NewReader&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;bytes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;NewReader&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Determine how many bytes to read.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;numBytesToRead&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Buffered&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;numBytesToRead&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;5&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;numBytesToRead&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;5&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Get a slice of the buffer.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Peek&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;numBytesToRead&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Discard the bytes read.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Discard&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;Peek&lt;&#x2F;code&gt; 方法会返回一个底层缓冲区的切片，这使得我们可以直接从缓冲区读取数据。处理完这些字节后，我们可以调用 &lt;code&gt;Discard&lt;&#x2F;code&gt; 来推进读取器的位置。因为 &lt;code&gt;Peek&lt;&#x2F;code&gt; 返回的切片指向的是底层的字节数组，所以当读取器位置被推进后，这个切片就不再有效，缓冲区内容可能已被覆盖。&lt;&#x2F;p&gt;
&lt;p&gt;我在实现自己的缓冲符文读取器（&lt;code&gt;buffered rune reader&lt;&#x2F;code&gt;，见 &lt;code&gt;ianlewis&#x2F;runeio&lt;&#x2F;code&gt;）时用了这种方式，这样调用者就可以对符文流进行窥视（&lt;code&gt;peek&lt;&#x2F;code&gt;），而无需推进读取器，同时实现零拷贝语义。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bufio-reader-1&quot;&gt;bufio.Reader&lt;a class=&quot;zola-anchor&quot; href=&quot;#bufio-reader-1&quot; aria-label=&quot;Anchor link for: bufio-reader-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;bufio.Reader 的作用:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bufio.Reader&lt;&#x2F;code&gt; 是对底层 &lt;code&gt;io.Reader&lt;&#x2F;code&gt; 的一个包装，里面有一个缓冲区（默认大小是 4096 字节）。&lt;&#x2F;li&gt;
&lt;li&gt;它的主要目的是减少系统调用次数，提高读取效率。&lt;&#x2F;li&gt;
&lt;li&gt;这是因为每次系统调用（比如从文件、网络读取数据）都比较慢，频繁调用性能会受影响。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;具体工作流程:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;当你调用 &lt;code&gt;bufio.Reader.Read&lt;&#x2F;code&gt; 读取数据时，如果缓冲区里的数据不够，它才会去底层调用一次系统调用，读取一大块数据（4096字节），先填满缓冲区。&lt;&#x2F;li&gt;
&lt;li&gt;这部分数据是要经过一次复制的，从文件或网络的数据被“搬运”到缓冲区。&lt;&#x2F;li&gt;
&lt;li&gt;接下来，程序继续从缓冲区读取数据，不再直接调用底层系统。这是优化点，减少多次系统调用。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;为什么这能提高性能:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;很多程序会运行“多次小量读取”操作，如果每次读取都调系统调用，从操作系统请求数据，效率很低。&lt;&#x2F;li&gt;
&lt;li&gt;用缓冲区先读大块数据，一次调用读入足够多的数据，后续读取直接从内存缓冲区拿数据，速度快很多。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;第一次复制无法避免，但后续复制可以避免吗？&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;第一次从操作系统读入缓冲区是必须的（这是物理数据进入内存中的步骤）。&lt;&#x2F;li&gt;
&lt;li&gt;正常情况下，如果程序要把数据进一步拷贝到另外一个切片或数组，这又是一次额外复制。&lt;&#x2F;li&gt;
&lt;li&gt;可以避免第二次从缓冲区复制到别的数组。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;怎么避免第二次复制？&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;使用 &lt;code&gt;bufio.Reader&lt;&#x2F;code&gt; 的以下方法：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Buffered()&lt;&#x2F;code&gt;: 返回当前缓冲区中累计了多少字节尚未读取，可以先知道缓冲区内数据量。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Peek(n int)&lt;&#x2F;code&gt;: 可以“偷看”缓冲区里前面&lt;code&gt;n&lt;&#x2F;code&gt;个字节的数据，返回的是缓冲区的切片引用，不复制数据（零拷贝读取）。这样你可以直接操作缓冲区里已有的数据。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Discard(n int)&lt;&#x2F;code&gt;: 丢弃缓冲区内前&lt;code&gt;n&lt;&#x2F;code&gt;个字节，对应已经读取或跳过的数据，更新缓冲区状态。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;结合使用 &lt;code&gt;Peek&lt;&#x2F;code&gt; 和 &lt;code&gt;Discard&lt;&#x2F;code&gt;，你就可以“读”缓冲区的数据而不做额外复制，只要数据足够，你操作的就是缓冲区的内存片段。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.ianlewis.org&#x2F;en&#x2F;zero-copy-readers-in-go&quot;&gt;https:&#x2F;&#x2F;www.ianlewis.org&#x2F;en&#x2F;zero-copy-readers-in-go&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Go | 跨包访问非导出符号</title>
          <pubDate>Mon, 21 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-21-call-unexported-fn-and-var/</link>
          <guid>https://inasa.dev/posts/25-04-21-call-unexported-fn-and-var/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-21-call-unexported-fn-and-var/">&lt;p&gt;&lt;code&gt;&#x2F;&#x2F;go:linkname&lt;&#x2F;code&gt; 是 &lt;code&gt;Go&lt;&#x2F;code&gt; 语言中的一个编译指令（&lt;code&gt;compiler directive&lt;&#x2F;code&gt;），用于在编译期间将一个符号（函数或变量）的名称重命名成另一个符号，达到在不同包之间绕过封装直接访问非导出（&lt;code&gt;unexported&lt;&#x2F;code&gt;）标识符的效果。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;需要导入 &lt;code&gt;unsafe&lt;&#x2F;code&gt; 包&lt;&#x2F;li&gt;
&lt;li&gt;函数或变量必须声明&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;shi-yong-wei-dao-chu-han-shu-shi-li-1&quot;&gt;使用未导出函数（示例1）：&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-yong-wei-dao-chu-han-shu-shi-li-1&quot; aria-label=&quot;Anchor link for: shi-yong-wei-dao-chu-han-shu-shi-li-1&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;mypkg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;unsafe&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-keyword z-annotation z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-punctuation z-accessor z-colon z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-variable z-function z-go&quot;&gt;linkname&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;privateFunc&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;runtime.internalFunc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;privateFunc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这里 &lt;code&gt;mypkg&lt;&#x2F;code&gt; 包里的 &lt;code&gt;privateFunc&lt;&#x2F;code&gt; 会被链接为 &lt;code&gt;runtime&lt;&#x2F;code&gt; 包中的非导出函数 &lt;code&gt;internalFunc&lt;&#x2F;code&gt;，调用&lt;code&gt;privateFunc()&lt;&#x2F;code&gt; 就是调用的 &lt;code&gt;runtime.internalFunc()&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shi-yong-wei-dao-chu-han-shu-shi-li-2&quot;&gt;使用未导出函数（示例2）：&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-yong-wei-dao-chu-han-shu-shi-li-2&quot; aria-label=&quot;Anchor link for: shi-yong-wei-dao-chu-han-shu-shi-li-2&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;    &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;unsafe&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;    &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;github.com&#x2F;xxx&#x2F;yyy&#x2F;zzz&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 确保包被导入
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-keyword z-annotation z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-punctuation z-accessor z-colon z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-variable z-function z-go&quot;&gt;linkname&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;newUUID&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;github.com&#x2F;xxx&#x2F;yyy&#x2F;zzz.newUUID&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;newUUID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;s&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;newUUID&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;shi-yong-wei-dao-chu-bian-liang&quot;&gt;使用未导出变量：&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-yong-wei-dao-chu-bian-liang&quot; aria-label=&quot;Anchor link for: shi-yong-wei-dao-chu-bian-liang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;yourpkg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;unsafe&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-keyword z-annotation z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-punctuation z-accessor z-colon z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-variable z-function z-go&quot;&gt;linkname&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;someValue&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;github.com&#x2F;xxx&#x2F;yyy&#x2F;zzz.someValue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;someValue&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</description>
      </item>
      <item>
          <title>转载 | Memory Models, Part 3-Updating the Go Memory Model</title>
          <pubDate>Mon, 21 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-21-updating-the-go-memory-model/</link>
          <guid>https://inasa.dev/posts/25-04-21-updating-the-go-memory-model/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-21-updating-the-go-memory-model/">&lt;p&gt;当前的Go语言内存模型是2009年编写的，自那以后只做了小幅更新。显然，至少有一些细节需要添加到当前的内存模型中，其中包括对数据竞争检测器的明确支持，以及对sync&#x2F;atomic同步程序中API使用方式的清晰说明。&lt;&#x2F;p&gt;
&lt;p&gt;这篇文章重申了Go语言的整体理念和当前的内存模型，然后概述了我认为应该对Go内存模型进行的相对较小的调整。文章假设读者了解早期文章“硬件内存模型”和“编程语言内存模型”中介绍的背景内容。&lt;&#x2F;p&gt;
&lt;p&gt;我已经开启了一个&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;s&#x2F;mm-discuss&quot;&gt;GitHub讨论&lt;&#x2F;a&gt;，以收集对这里提出的想法的反馈。基于这些反馈，我计划在本月晚些时候准备一份正式的Go提案。GitHub讨论本身也是一种试验，目的是继续&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;proposals-discuss&quot;&gt;寻找一种合理方式来扩展对重要变更的讨论&lt;&#x2F;a&gt;。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;go-s-design-philosophy&quot;&gt;Go’s Design Philosophy&lt;a class=&quot;zola-anchor&quot; href=&quot;#go-s-design-philosophy&quot; aria-label=&quot;Anchor link for: go-s-design-philosophy&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Go旨在成为一个用于构建实用且高效系统的编程环境。它旨在对小型项目保持轻量，同时也能优雅地扩展到大型项目和大型工程团队。&lt;&#x2F;p&gt;
&lt;p&gt;Go鼓励以高级别处理并发，特别是通过通信。Go的&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;go-proverbs.github.io&#x2F;&quot;&gt;第一个箴言&lt;&#x2F;a&gt;是“不要通过共享内存来通信，而要通过通信来共享内存。”另一个流行的箴言是“清晰胜于巧妙。”换句话说，Go鼓励通过避免复杂代码来避免隐晦的错误。&lt;&#x2F;p&gt;
&lt;p&gt;Go不仅旨在实现易于理解的程序，还致力于实现易于理解的语言和易于理解的包API。复杂或微妙的语言特性或API与这一目标相矛盾。正如托尼·霍尔在他的&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.cs.fsu.edu&#x2F;~engelen&#x2F;courses&#x2F;COP4610&#x2F;hoare.pdf&quot;&gt;1980年图灵奖&lt;&#x2F;a&gt;演讲中所说：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;我得出结论，构建软件设计有两种方法：一种是将设计做得如此简单，以至于显然没有缺陷；另一种是将设计做得如此复杂，以至于没有明显的缺陷。&lt;&#x2F;p&gt;
&lt;p&gt;第一种方法要困难得多。它要求具备与发现自然界复杂现象背后的简单物理定律相同的技能、奉献、洞察力，甚至灵感。它还需要接受因物理、逻辑和技术限制而设定的目标，并在目标冲突无法调和时做出妥协。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;这与Go对API的理念非常契合。我们通常会在设计过程中花费大量时间，确保API设计正确，努力将其简化到最小、最有用的本质。&lt;&#x2F;p&gt;
&lt;p&gt;Go作为一个有用编程环境的另一个方面是它为最常见的编程错误定义了明确的语义，这有助于理解和调试。这个理念并不新颖。再次引用托尼·霍尔的话，这次是他在1972年的&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;onlinelibrary.wiley.com&#x2F;doi&#x2F;abs&#x2F;10.1002&#x2F;spe.4380020202&quot;&gt;“软件质量”清单&lt;&#x2F;a&gt;中说：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“一款软件程序不仅要非常简洁易用，还必须非常难以被误用；它必须对编程错误表现出宽容，清楚地指示错误的发生，并且其影响绝不应变得不可预测。”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;对于有缺陷程序定义明确语义的常识并不像预期的那样普遍。在C&#x2F;C++中，未定义行为已经演变成编译器作者的一种“完全自由裁量权”，能够将稍有缺陷的程序变成行为截然不同的问题程序，方式越来越有趣。Go不采用这种方式：Go不存在“未定义行为”。特别是，像空指针解引用、整数溢出和非故意的无限循环这些错误在Go中都有明确定义的语义。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;go-s-memory-model-today&quot;&gt;Go’s Memory Model Today&lt;a class=&quot;zola-anchor&quot; href=&quot;#go-s-memory-model-today&quot; aria-label=&quot;Anchor link for: go-s-memory-model-today&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;ref&#x2F;mem&quot;&gt;Go的内存模型&lt;&#x2F;a&gt;以以下建议开始，这与Go的整体理念一致：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;修改被多个goroutine同时访问的数据的程序，必须对这种访问进行序列化。&lt;&#x2F;p&gt;
&lt;p&gt;为了序列化访问，可以使用通道操作或其他同步原语来保护数据，比如sync和sync&#x2F;atomic包中的同步原语。&lt;&#x2F;p&gt;
&lt;p&gt;如果你必须阅读本文档的其余部分才能理解程序的行为，那说明你的程序设计过于巧妙。&lt;&#x2F;p&gt;
&lt;p&gt;不要过于聪明。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;这依然是很好的建议。这条建议也与其他语言鼓励使用DRF-SC（数据竞态自由-顺序一致性）的理念一致：通过同步来消除数据竞争，从而使程序表现得像是顺序一致的，无需理解内存模型的其余部分。&lt;&#x2F;p&gt;
&lt;p&gt;在上述建议之后，Go内存模型定义了一个基于传统“先行发生”关系的竞态读写定义。类似于Java和JavaScript，Go中的一次读取可以观察到发生在先但尚未被覆盖的写操作，或者任何竞态写操作；安排只有一个此类写操作会强制产生特定结果。&lt;&#x2F;p&gt;
&lt;p&gt;随后，内存模型定义了建立跨goroutine先行发生边界的同步操作。这些操作是常见的操作，并带有一些Go特有的特征：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;如果包p导入了包q，则q的init函数执行完成先于p中任何函数的开始。&lt;&#x2F;li&gt;
&lt;li&gt;main.main函数的开始发生在所有init函数完成之后。&lt;&#x2F;li&gt;
&lt;li&gt;启动新goroutine的go语句发生在该goroutine执行之前。&lt;&#x2F;li&gt;
&lt;li&gt;通道上的发送操作先于对应的接收完成。&lt;&#x2F;li&gt;
&lt;li&gt;关闭通道先于接收返回零值（因通道关闭）。&lt;&#x2F;li&gt;
&lt;li&gt;从无缓冲通道接收先于该通道上的发送完成。&lt;&#x2F;li&gt;
&lt;li&gt;容量为C的通道上的第k次接收先于第k+C次发送完成。&lt;&#x2F;li&gt;
&lt;li&gt;对于任何sync.Mutex或sync.RWMutex变量l，且n &amp;lt; m，l.Unlock()的第n次调用发生在第m次l.Lock()的调用之前。&lt;&#x2F;li&gt;
&lt;li&gt;once.Do(f)中单次调用f()的执行（返回）发生在任何once.Do(f)调用返回之前。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;值得注意的是，该列表未提及sync&#x2F;atomic及sync包中的较新API。&lt;&#x2F;p&gt;
&lt;p&gt;内存模型以一些错误同步的示例结束，但不包含任何错误编译的示例。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;changes-to-go-s-memory-model&quot;&gt;Changes to Go’s Memory Model&lt;a class=&quot;zola-anchor&quot; href=&quot;#changes-to-go-s-memory-model&quot; aria-label=&quot;Anchor link for: changes-to-go-s-memory-model&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;2009年，当我们着手编写Go的内存模型时，Java内存模型刚刚修订完毕，C&#x2F;C++11内存模型也在最终定稿阶段。有人强烈建议我们采用C&#x2F;C++11模型，利用其所做的大量工作，但我们认为这风险较大。相反，我们决定采取更为保守的方式来保证内存模型的可靠性，这一决策得到了随后十年大量论文的支持，这些论文详细阐述了Java&#x2F;C&#x2F;C++内存模型中的一些非常微妙的问题。为程序员和编译器作者制定足够的内存模型指导非常重要，但制定一个完全形式化且正确的定义，似乎仍超出了最有才华的研究人员的掌控范围。对于Go来说，能够继续声明所需的最小标准以保持实用性就已经足够了。&lt;&#x2F;p&gt;
&lt;p&gt;本节列出了我认为应做的调整。正如之前提到的，我已开启了一场GitHub讨论以收集反馈。基于这些反馈，我计划在本月晚些时候准备一份正式的Go提案。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;document-go-s-overall-approach&quot;&gt;Document Go’s overall approach&lt;a class=&quot;zola-anchor&quot; href=&quot;#document-go-s-overall-approach&quot; aria-label=&quot;Anchor link for: document-go-s-overall-approach&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;“不要过于聪明”的建议很重要，也应该保留，但我们在深入讨论先行发生细节之前，还需要更多地说明Go的整体方法。我见过多种对Go方法的错误总结，比如声称Go的模型是C&#x2F;C++的“DRF-SC或Catch Fire（即要么数据无竞争顺序一致性，要么程序爆炸）”。这样的误读是可以理解的：文档没有明确说明该方法是什么，而且内容非常简短（且材料十分微妙），人们往往看到的是他们期望看到的内容，而非真实存在或不存在的内容。&lt;&#x2F;p&gt;
&lt;p&gt;需要补充的文本大致会是如下内容：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;概述&lt;&#x2F;p&gt;
&lt;p&gt;Go对其内存模型的处理方式与语言的整体设计理念类似，旨在保持语义的简单、易懂且实用。&lt;&#x2F;p&gt;
&lt;p&gt;数据竞争（data race）被定义为对同一内存位置的写操作与另一个同时进行的读或写操作，除非所有相关访问都是sync&#x2F;atomic包提供的原子数据访问。如前所述，强烈鼓励程序员使用适当的同步机制以避免数据竞争。在无数据竞争的情况下，Go程序表现得好像所有goroutine都被多路复用到了单个处理器上。这一特性有时称为DRF-SC：无数据竞争的程序以顺序一致的方式执行。&lt;&#x2F;p&gt;
&lt;p&gt;其他编程语言通常对包含数据竞争的程序采取两种处理方式之一。第一种方式，以C和C++为代表，认为包含数据竞争的程序是无效的：编译器可能以不可预期的方式破坏这些程序。第二种方式，以Java和JavaScript为代表，认为包含数据竞争的程序有定义的语义，限制了数据竞争的可能影响，使程序更可靠且更易调试。Go的方法介于这两者之间。带有数据竞争的程序在某种意义上是无效的，因为实现可以检测到数据竞争并终止程序。但除此之外，带有数据竞争的程序具有定义的语义，且有有限的可能结果，使错误程序更可靠且更易调试。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;这段文字应当明确说明Go语言与其他语言的异同，纠正读者之前可能存在的误解。&lt;&#x2F;p&gt;
&lt;p&gt;在“先行发生（Happens Before）”部分的结尾，我们还应澄清某些数据竞争仍然可能导致数据损坏。目前该部分结尾为：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;比单个机器字更大的值的读写操作表现为多次以机器字大小为单位的操作，且顺序未指定。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;我们应补充说明：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;请注意，这意味着对多字数据结构的竞争可能导致不一致的值，这些值并不对应于单次写入。当值依赖于内部一致性的（指针、长度）或（指针、类型）对时，如大多数Go实现中的接口值、映射、切片和字符串，这类竞争反过来可能导致任意内存损坏。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;这样可以更清楚地说明存在数据竞争程序的保证限制。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;document-happens-before-for-sync-libraries&quot;&gt;Document happens-before for sync libraries&lt;a class=&quot;zola-anchor&quot; href=&quot;#document-happens-before-for-sync-libraries&quot; aria-label=&quot;Anchor link for: document-happens-before-for-sync-libraries&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;自内存模型编写以来，&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;pkg&#x2F;sync&quot;&gt;sync包&lt;&#x2F;a&gt;中新增了若干API。我们需要将它们添加到内存模型中（见 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;issue&#x2F;7948&quot;&gt;issue #7948&lt;&#x2F;a&gt;）。幸运的是，新增内容似乎比较直接。我认为它们包括以下内容：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;对于 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;pkg&#x2F;sync&#x2F;#Cond&quot;&gt;sync.Cond&lt;&#x2F;a&gt;：Broadcast 或 Signal 操作发生在解除阻塞的任何 Wait 调用返回之前。&lt;&#x2F;li&gt;
&lt;li&gt;对于 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;pkg&#x2F;sync&#x2F;#Map&quot;&gt;sync.Map&lt;&#x2F;a&gt;：Load、LoadAndDelete 和 LoadOrStore 是读取操作。Delete、LoadAndDelete 和 Store 是写入操作。当 LoadOrStore 返回时，会将 loaded 设置为 false。写入操作发生在任何观察写入效果的读取操作之前。&lt;&#x2F;li&gt;
&lt;li&gt;对于 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;pkg&#x2F;sync&#x2F;#Pool&quot;&gt;sync.Pool&lt;&#x2F;a&gt;：调用 Put(x) 发生在调用 Get 并返回相同值 x 之前。同样，调用返回 x 的 New 发生在调用 Get 返回该相同值 x 之前。&lt;&#x2F;li&gt;
&lt;li&gt;对于 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;pkg&#x2F;sync&#x2F;#WaitGroup&quot;&gt;sync.WaitGroup&lt;&#x2F;a&gt;：调用 Done 发生在解除阻塞的任何 Wait 调用返回之前。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;这些API的使用者需要了解这些保证，以便有效地使用它们。因此，虽然我们应在内存模型文本中保留这些说明以作示例，但也应将其加入 sync 包的文档注释中。这同样能为第三方同步原语树立一个良好的示范，即文档化API中定义的排序保证的重要性。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;document-happens-before-for-sync-atomic&quot;&gt;Document happens-before for sync&#x2F;atomic&lt;a class=&quot;zola-anchor&quot; href=&quot;#document-happens-before-for-sync-atomic&quot; aria-label=&quot;Anchor link for: document-happens-before-for-sync-atomic&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;内存模型中缺少原子操作。我们需要将它们添加进去（见 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;golang.org&#x2F;issue&#x2F;5045&quot;&gt;issue #5045&lt;&#x2F;a&gt;）。我认为应说明：&lt;&#x2F;p&gt;
&lt;p&gt;sync&#x2F;atomic 包中的API统称为“原子操作”，可用于同步不同goroutine的执行。如果原子操作B观察到原子操作A的效果，则A发生在B之前。程序中执行的所有原子操作表现得好像按照某种顺序（顺序一致顺序）执行。&lt;&#x2F;p&gt;
&lt;p&gt;这是&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;issues&#x2F;5045#issuecomment-66076297&quot;&gt;Dmitri Vyukov在2013年提出的建议&lt;&#x2F;a&gt;，也是我在&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;issues&#x2F;5045#issuecomment-252730563&quot;&gt;2016年非正式承诺的内容&lt;&#x2F;a&gt;。它的语义与Java的volatile和C++的默认原子操作相同。&lt;&#x2F;p&gt;
&lt;p&gt;关于C&#x2F;C++中的原子同步选项，只有两种：顺序一致性（sequentially consistent）或获取&#x2F;释放（acquire&#x2F;release）。（放宽的原子操作不会产生先行发生边缘，因此没有同步效果。）在两者之间的选择主要取决于两个方面：第一，能够推理多个位置上原子操作的相对顺序有多重要；第二，顺序一致性原子操作相比于获取&#x2F;释放原子操作，代价高多少。&lt;&#x2F;p&gt;
&lt;p&gt;对于第一个方面，推理多个位置上的原子操作相对顺序非常重要。在之前的一篇文章中，我给出了&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;plmm#cond&quot;&gt;一个使用两个原子变量实现的无锁条件变量快速路径的示例&lt;&#x2F;a&gt;，这个实现被获取&#x2F;释放原子操作破坏了。类似的模式反复出现。例如，sync.WaitGroup的早期实现使用了&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;go.googlesource.com&#x2F;go&#x2F;+&#x2F;ee6e1a3ff77a41eff5a606a5aa8c46bf8b571a13&#x2F;src&#x2F;pkg&#x2F;sync&#x2F;waitgroup.go#54&quot;&gt;一对原子uint32值&lt;&#x2F;a&gt;，wg.counter和wg.waiters。&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;go.googlesource.com&#x2F;go&#x2F;+&#x2F;cf148f3d468f4d0648e7fc6d2858d2afdc37f70d&#x2F;src&#x2F;runtime&#x2F;sema.go#134&quot;&gt;Go运行时中信号量&lt;&#x2F;a&gt;的实现也依赖于两个独立的原子字，分别是信号量值*addr和对应的等待者计数root.nwait。还有更多类似的情况。若缺乏顺序一致语义（即改用获取&#x2F;释放语义时），人们仍会写出类似的代码；只是这些代码会神秘地失败，而且只会在特定上下文中出现问题。&lt;&#x2F;p&gt;
&lt;p&gt;根本问题在于，使用获取&#x2F;释放（acquire&#x2F;release）原子操作来实现程序无数据竞争（data-race-free）并不会使程序表现出顺序一致性行为，因为原子操作本身并不具备这种特性。也就是说，这类程序不具备DRF-SC（无数据竞争即顺序一致性）的保证。这使得此类程序非常难以推理，因此也难以正确编写。&lt;&#x2F;p&gt;
&lt;p&gt;关于第二点，正如早期文章中提到的，&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;plmm#sc&quot;&gt;硬件设计者开始直接支持顺序一致性原子操作&lt;&#x2F;a&gt;。例如，ARMv8增加了ldar和stlr指令用于实现顺序一致性的原子操作，它们也是&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;~pes20&#x2F;cpp&#x2F;cpp0xmappings.html&quot;&gt;实现获取&#x2F;释放原子操作的推荐方案&lt;&#x2F;a&gt;。如果我们对sync&#x2F;atomic采用获取&#x2F;释放语义，那么ARMv8上的程序本来就会获得顺序一致性。毫无疑问，这会导致依赖更强排序保证的程序在更弱的平台上意外出错。即使在单一架构上，如果获取&#x2F;释放和顺序一致性原子操作之间的差异因为数据竞争窗口较小时难以观察到，这种情况也可能发生。&lt;&#x2F;p&gt;
&lt;p&gt;这两点都强烈表明我们应当采用顺序一致性原子操作，而不是获取&#x2F;释放原子操作：顺序一致性原子更有用，而且一些芯片已经完全消除了这两种级别之间的差距。如果差距显著，估计其他芯片也会跟进。&lt;&#x2F;p&gt;
&lt;p&gt;同样的考量，加上Go整体追求简洁且易理解的API的设计哲学，也反对将获取&#x2F;释放作为额外的、并行的一组API提供。看起来最好只提供最易理解、最实用、最不易被误用的一组原子操作。&lt;&#x2F;p&gt;
&lt;p&gt;另一种可能是提供原始屏障（barriers）而非原子操作。（C++当然两者皆有。）屏障的缺点是使得期望不那么明确，且相对更依赖架构。Hans Boehm 的文章&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.hboehm.info&#x2F;c++mm&#x2F;ordering_integrated.html&quot;&gt;“Why atomics have integrated ordering constraints”&lt;&#x2F;a&gt;提出了提供原子操作而非屏障的理由（他使用fences一词指屏障）。一般来说，原子操作比屏障更容易理解，而且既然我们今天已经提供了原子操作，就不容易取消它们。宁可只用一种机制，而不是两种。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;maybe-add-a-typed-api-to-sync-atomic&quot;&gt;Maybe: Add a typed API to sync&#x2F;atomic&lt;a class=&quot;zola-anchor&quot; href=&quot;#maybe-add-a-typed-api-to-sync-atomic&quot; aria-label=&quot;Anchor link for: maybe-add-a-typed-api-to-sync-atomic&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;上述定义说明，当某块内存必须被多个 goroutine 并发访问且没有其他同步手段时，消除数据竞争的唯一方法是让所有访问操作都使用原子操作。仅让部分访问使用原子操作是不够的。例如，一个非原子写操作与原子读写操作并发仍然构成竞争，原子写操作与非原子读写并发也同样构成竞争。&lt;&#x2F;p&gt;
&lt;p&gt;因此，是否应对特定值使用原子操作是该值的属性，而不是某个具体访问的属性。基于这一点，大多数语言会将这类信息纳入类型系统中，比如 Java 的 volatile int 和 C++ 的 atomic。而 Go 目前的 API 并没有这样做，这意味着正确使用需要仔细注释结构体字段或全局变量，指明哪些字段或变量预计只应通过原子 API 访问。&lt;&#x2F;p&gt;
&lt;p&gt;为了提升程序的正确性，我开始认为 Go 应该定义一套有类型的原子值，类似于当前的 atomic.Value：包括 Bool、Int、Uint、Int32、Uint32、Int64、Uint64 以及 Uintptr。像 Value 一样，这些类型应该具备 CompareAndSwap、Load、Store 和 Swap 方法。例如：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Int32&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;v&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Int32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Add&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;delta&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;AddInt32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;delta&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Int32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;CompareAndSwap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;old&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;swapped&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;CompareAndSwapInt32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;old&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Int32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Load&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;LoadInt32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Int32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Store&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;v&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;StoreInt32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Int32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Swap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;old&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;SwapInt32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;我将 Bool 包含在列表中，是因为我们在 Go 标准库中（未导出的 API）多次用原子整数构造了原子布尔值，显然有这种需求。&lt;&#x2F;p&gt;
&lt;p&gt;我们还可以利用即将支持的泛型，定义一个针对原子指针的 API，使其具备类型安全且不依赖于 unsafe 包的特性。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;any&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;v&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;T&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;p&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;[&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;T&lt;&#x2F;span&gt;]&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;CompareAndSwap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;old&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;new&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;swapped&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;CompareAndSwapPointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;lots&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;of&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;unsafe&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;（诸如此类。）针对一个明显的建议，我认为目前还没有简洁的方法利用泛型来提供单一的 &lt;code&gt;atomic.Atomic[T]&lt;&#x2F;code&gt;，从而避免引入 Bool、Int 等作为单独类型，至少在没有编译器中特殊处理的情况下是如此。这也没关系。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;maybe-add-unsynchronized-atomics&quot;&gt;Maybe: Add unsynchronized atomics&lt;a class=&quot;zola-anchor&quot; href=&quot;#maybe-add-unsynchronized-atomics&quot; aria-label=&quot;Anchor link for: maybe-add-unsynchronized-atomics&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;所有其他现代编程语言都提供了一种方式，使得并发的内存读写操作不会同步程序，但也不会使程序失效（即不算作数据竞争）。C、C++、Rust 和 Swift 都支持放宽的原子操作。Java 有 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;9&#x2F;docs&#x2F;api&#x2F;java&#x2F;lang&#x2F;invoke&#x2F;VarHandle.html&quot;&gt;VarHandle 的“plain”模式&lt;&#x2F;a&gt;。JavaScript 对 SharedArrayBuffer（唯一的共享内存）进行非原子访问。Go 没有这种做法。也许应该有，我也不确定。&lt;&#x2F;p&gt;
&lt;p&gt;如果我们想添加不同步的原子读写，可以给有类型的原子类型增加 UnsyncAdd、UnsyncCompareAndSwap、UnsyncLoad、UnsyncStore 和 UnsyncSwap 方法。给它们命名为“unsync”可以避免一些与“relaxed”命名相关的问题。首先，有些人把 relaxed 用作相对比较，比如“acquire&#x2F;release”是比顺序一致性更宽松的内存序。你可能会说这不是该术语的正确用法，但确实存在。其次，更重要的是，这些操作的关键细节不是其自身的内存顺序，而是它们对程序其余部分同步没有任何影响。对不熟悉内存模型的人来说，看到 UnsyncLoad 应该明确它没有同步作用，而 RelaxedLoad 可能不会这么明显。此外，Unsync 看起来像 Unsafe，这也挺好的。&lt;&#x2F;p&gt;
&lt;p&gt;API 讨论暂且放一边，真正的问题是是否应该添加这些不同步的原子操作。支持添加的常见理由是，对于某些数据结构中的快速路径性能确实非常重要。我的总体印象是，这种性能提升主要体现在非 x86 架构上，虽然我没有数据支持这一点。不提供不同步的原子操作可能会对这些架构不利。&lt;&#x2F;p&gt;
&lt;p&gt;反对提供不同步原子的可能论点是，在 x86 平台上，如果忽略编译器重排序的潜在影响，不同步原子操作与 acquire&#x2F;release 原子操作无法区分。因此，这可能被滥用，导致代码只能在 x86 上正常工作。反驳是，这种狡诈手法不会通过竞态检测器的检测，因为竞态检测器实施的是实际的内存模型，而不是 x86 的内存模型。&lt;&#x2F;p&gt;
&lt;p&gt;鉴于目前缺乏证据，我们没有理由去添加这个 API。如果有人强烈认为应该添加，合理的做法是先收集两方面的证据：（1）程序员需要编写的代码中此功能的普遍适用性；（2）在广泛使用的系统中利用不同步原子操作带来的显著性能提升。（用其他语言中的程序来展示也可以。）&lt;&#x2F;p&gt;
&lt;h3 id=&quot;document-disallowed-compiler-optimizations&quot;&gt;Document disallowed compiler optimizations&lt;a class=&quot;zola-anchor&quot; href=&quot;#document-disallowed-compiler-optimizations&quot; aria-label=&quot;Anchor link for: document-disallowed-compiler-optimizations&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;当前的内存模型以给出无效程序的示例作为结尾。既然内存模型充当了程序员与编译器开发者之间的契约，我们应该增加无效的编译器优化示例。例如，我们可以添加：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;错误的编译优化&lt;&#x2F;p&gt;
&lt;p&gt;Go 的内存模型对编译器优化的限制和对 Go 程序的限制同样严格。有些在单线程程序中有效的编译器优化，在 Go 程序中却无效。特别是，编译器不得在无数据竞争的程序中引入数据竞争，不能允许单次读取观察到多个值，也不能允许单次写入写入多个值。&lt;&#x2F;p&gt;
&lt;p&gt;不在无数据竞争程序中引入数据竞争，意味着不能将读取或写入操作移出它们所在的条件语句。例如，编译器不得将以下程序中的条件反转：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;cond&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;   &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;也就是说，编译器不得将程序重写成如下形式：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;cond&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;   &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;如果条件 cond 为假且另一个 goroutine 正在写入 *p，那么原程序是无数据竞争的，但重写后的程序却包含数据竞争。&lt;&#x2F;p&gt;
&lt;p&gt;不引入数据竞争还意味着不能假设循环会终止。例如，编译器不得将对 *p 或 *q 的访问移到以下程序的循环之前：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;e&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;list&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;e&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;e&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;next&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;   &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;++&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;q&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;如果 list 指向一个循环链表，那么原程序永远不会访问 *p 或 *q，但重写后的程序却会。&lt;&#x2F;p&gt;
&lt;p&gt;不引入数据竞争还意味着不能假设被调用的函数总是返回或不包含同步操作。例如，编译器不得将对 *p 或 *q 的访问移到以下程序中的函数调用之前（至少在不了解函数 f 的具体行为的情况下）：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;q&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;如果函数调用从未返回，那么原程序依然永远不会访问 *p 或 *q，但重写后的程序会。如果函数调用包含同步操作，那么原程序可以建立在访问 *p 和 *q 之前发生的“先行”关系，而重写后的程序则不能。&lt;&#x2F;p&gt;
&lt;p&gt;不允许单次读取观察到多个值意味着不能从共享内存中重新加载局部变量。例如，编译器不得将变量 i 溢出到内存中，并在这个程序中从 *p 第二次重新加载它：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;||&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;&amp;gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;funcs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;   &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;panic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;invalid function index&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;complex&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;code&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; compiler must NOT reload i = *p here
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;funcs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;如果复杂代码需要许多寄存器，针对单线程程序的编译器可能会在调用 &lt;code&gt;funcs[i]()&lt;&#x2F;code&gt; 前丢弃变量 i，不做复制，然后重新加载 i = *p。而 Go 编译器不能这样做，因为 *p 的值可能已经改变了。（相反，编译器可以将 i 溢出到栈上。）&lt;&#x2F;p&gt;
&lt;p&gt;不允许单次写操作写入多个不同的值也意味着不能使用局部变量写入之前的内存作为临时存储。例如，编译器不得在这个程序中将 *p 用作临时存储：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;也就是说，编译器不得将程序重写成如下形式：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;&#x2F;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;2&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;+=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;如果 i 和 *p 初始都等于 2，原代码执行 *p = 3，因此竞争线程只能从 *p 读到 2 或 3。重写后的代码先执行 *p = 1，再执行 *p = 3，使得竞争线程也能读到 1。&lt;&#x2F;p&gt;
&lt;p&gt;需要注意的是，所有这些优化在 C&#x2F;C++ 编译器中是允许的：使用与 C&#x2F;C++ 编译器共用后端的 Go 编译器必须注意禁用对 Go 无效的优化。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;这些类别和示例涵盖了与数据竞争访问定义语义不兼容的最常见的 C&#x2F;C++ 编译器优化。它们明确表明 Go 和 C&#x2F;C++ 有不同的要求。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusion&quot; aria-label=&quot;Anchor link for: conclusion&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Go在其内存模型上采取保守的总体方法，这对我们非常有利，且应继续保持。然而，有一些迟来的变更是必要的，包括定义sync和sync&#x2F;atomic包中新API的同步行为。特别是原子操作应被明确记录，以提供顺序一致的行为，创建发生前边缘，确保同步非原子代码。这将与所有其他现代系统语言默认提供的原子操作一致。&lt;&#x2F;p&gt;
&lt;p&gt;此次更新最独特的部分或许是明确指出程序中存在数据竞争时，程序可以被停止以报告竞争情况，但这些程序在其他方面仍具有明确定义的语义。这一限制既约束了程序员，也约束了编译器，并且优先考虑了并发程序的可调试性和正确性，而非编译器编写者的便利。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;acknowledgements&quot;&gt;Acknowledgements&lt;a class=&quot;zola-anchor&quot; href=&quot;#acknowledgements&quot; aria-label=&quot;Anchor link for: acknowledgements&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;这系列文章得益于我在谷歌有幸共事的一长串工程师们的讨论和反馈。感谢他们。我对任何错误或不受欢迎的观点承担全部责任。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;gomm&quot;&gt;https:&#x2F;&#x2F;research.swtch.com&#x2F;gomm&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | Memory Models, Part 2-Programming Language Memory Models</title>
          <pubDate>Sat, 19 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-19-programming-language-memory-models/</link>
          <guid>https://inasa.dev/posts/25-04-19-programming-language-memory-models/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-19-programming-language-memory-models/">&lt;p&gt;编程语言内存模型回答了一个问题：并行程序可以依赖什么样的行为在它们的线程之间共享内存。例如，考虑下面这个用类似C语言编写的程序，其中x和done初始值都为零。&lt;&#x2F;p&gt;
&lt;div style=&quot;display: flex; justify-content: space-between; font-family: monospace; white-space: pre; width: 400px;&quot;&gt;
  &lt;div style=&quot;width: 45%;&quot;&gt;
&#x2F;&#x2F; Thread 1
x = 1;
done = 1;
  &lt;&#x2F;div&gt;
  &lt;div style=&quot;width: 45%;&quot;&gt;
&#x2F;&#x2F; Thread 2
while(done == 0) { &#x2F;* loop *&#x2F; }
print(x);
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;程序尝试从线程1向线程2发送一个x的消息，使用done作为消息准备好被接收的信号。如果线程1和线程2分别在各自专用的处理器上运行，并且都运行到完成，这个程序是否保证能够按预期执行完毕并打印1？编程语言内存模型回答了这个以及类似的问题。&lt;&#x2F;p&gt;
&lt;p&gt;虽然每种编程语言在细节上有所不同，但一些通用的结论基本适用于所有现代多线程语言，包括C、C++、Go、Java、JavaScript、Rust和Swift：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;首先，如果x和done是普通变量，那么线程2的循环可能永远不会停止。一个常见的编译器优化是在变量首次使用时将其加载到寄存器中，然后在后续访问中尽可能重复使用该寄存器。如果线程2在线程1执行之前就将done复制到寄存器，它可能会在整个循环过程中一直使用该寄存器，永远不会注意到线程1后来修改了done。&lt;&#x2F;li&gt;
&lt;li&gt;其次，即使线程2的循环停止了，观察到done == 1后，它仍可能打印出x是0。编译器经常根据优化启发式方法重新排序程序的读写操作，或者仅仅因为哈希表或其他中间数据结构在生成代码时遍历的顺序不同，线程1的编译代码可能会在done之前写入x，或者线程2的编译代码可能会在循环开始前读取x。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;鉴于这个程序有如此多的问题，显而易见的问题是如何修复它。&lt;&#x2F;p&gt;
&lt;p&gt;现代语言提供了特殊功能，以原子变量或原子操作的形式，允许程序同步其线程。如果将done设为原子变量（或在使用支持该方法的语言中通过原子操作操作它），那么程序就能保证执行完成并打印出1。将done设为原子变量有许多影响：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;线程1的编译代码必须确保对x的写入完成，并且在线程对done的写入变得可见之前，对其他线程也是可见的。&lt;&#x2F;li&gt;
&lt;li&gt;线程2的编译代码必须在每次循环迭代中读取（重新读取）done。&lt;&#x2F;li&gt;
&lt;li&gt;线程2的编译代码必须在线程2读取done之后，再读取x。&lt;&#x2F;li&gt;
&lt;li&gt;编译代码必须采取必要措施禁用那些可能重新引入上述问题的硬件优化。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;将done设为原子变量的最终效果是，使程序按预期行为运行，成功地将x的值从线程1传递到线程2。&lt;&#x2F;p&gt;
&lt;p&gt;在原始程序中，经过编译器代码重排序后，线程1可能在线程2读取x的同时写入x。这就是所谓的数据竞争（data race）。在修改后的程序中，原子变量done用于同步对x的访问：线程1不可能在线程2读取x的同时写入x。该程序是无数据竞争（data-race-free）的。一般来说，现代语言保证无数据竞争的程序总是以顺序一致的方式执行，仿佛来自不同线程的操作被交错执行，任意但不改变顺序地映射到单个处理器上。这就是在编程语言上下文中采用的&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;hwmm#drf&quot;&gt;硬件内存模型中的DRF-SC性质&lt;&#x2F;a&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;顺便说一句，这些原子变量或原子操作更恰当的称呼是“同步原子”（synchronizing atomics）。这些操作在数据库意义上是原子的，允许同时进行读写，其行为就像按某种顺序串行执行一样：普通变量上会发生的数据竞争在使用原子操作时就不会发生了。但更重要的是，这些原子操作能够同步程序的其余部分，提供一种方式消除非原子数据上的竞争。标准术语就是简单地称为“原子”（atomic），这正是本文所用的，只需记住在阅读“atomic”时应理解为“同步原子”，除非另有说明。&lt;&#x2F;p&gt;
&lt;p&gt;编程语言内存模型具体规定了程序员和编译器的确切要求，作为双方之间的契约。以上概述的通用特征适用于几乎所有现代语言，但直到最近，这些领域才趋于统一：在21世纪初，语言之间的区别明显更多。即便在今天，各种语言在以下二阶问题上仍存在显著差异，包括：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;原子变量自身的顺序保证是什么？&lt;&#x2F;li&gt;
&lt;li&gt;变量能否被同时以原子和非原子操作访问？&lt;&#x2F;li&gt;
&lt;li&gt;除了原子操作，还有其他同步机制吗？&lt;&#x2F;li&gt;
&lt;li&gt;是否存在不进行同步的原子操作？&lt;&#x2F;li&gt;
&lt;li&gt;含有数据竞争的程序是否有任何保证？&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;在进行一些基础介绍后，本文将探讨不同语言如何回答这些及相关问题，以及它们所采取的路径。文章还会强调许多错误的起点，以强调我们仍在学习什么方法有效、什么方法无效。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hardware-litmus-tests-happens-before-and-drf-sc-ying-jian-shi-jin-shi-ce-shi-xian-yu-guan-xi-ji-drf-sc&quot;&gt;Hardware, Litmus Tests, Happens Before, and DRF-SC(硬件、试金石测试、“先于”关系及DRF-SC)&lt;a class=&quot;zola-anchor&quot; href=&quot;#hardware-litmus-tests-happens-before-and-drf-sc-ying-jian-shi-jin-shi-ce-shi-xian-yu-guan-xi-ji-drf-sc&quot; aria-label=&quot;Anchor link for: hardware-litmus-tests-happens-before-and-drf-sc-ying-jian-shi-jin-shi-ce-shi-xian-yu-guan-xi-ji-drf-sc&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;在深入了解任何具体语言的细节之前，先简要总结一下我们需要牢记的硬件内存模型中的一些经验教训。&lt;&#x2F;p&gt;
&lt;p&gt;不同的架构允许不同程度的指令重排序，因此在多处理器上并行运行的代码，其允许的结果会因架构而异。黄金标准是&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;hwmm#sc&quot;&gt;顺序一致性（sequential consistency）&lt;&#x2F;a&gt;，即任何执行都必须表现得像程序在不同处理器上执行的操作以某种顺序被简单地交织到单个处理器上一样。该模型更容易让开发者推理理解，但由于性能优化带来的权衡，目前没有主流架构提供这种严格保证。&lt;&#x2F;p&gt;
&lt;p&gt;很难对不同的内存模型做出完全笼统的比较。相反，关注具体的测试用例——称为试金石测试（litmus tests）——会更有帮助。如果两个内存模型对某个特定的试金石测试表现出不同的行为，这就证明它们是不同的，并且通常能够帮助我们判断，在该测试用例上，某个模型是比另一个模型更弱还是更强。例如，下面是我们之前分析的程序对应的试金石测试形式：&lt;&#x2F;p&gt;
&lt;div&gt;
  &lt;p&gt;&lt;em&gt;litmus 测试：消息传递&lt;&#x2F;em&gt;&lt;br&gt;
  这个程序能观察到 r1 = 1，r2 = 0 吗？&lt;&#x2F;p&gt;
  &lt;div style=&quot;font-family: monospace; white-space: pre; padding: 10px; border-radius: 5px;&quot;&gt;
&#x2F;&#x2F; 线程 1              &#x2F;&#x2F; 线程 2
x = 1                  r1 = y
y = 1                  r2 = x
  &lt;&#x2F;div&gt;
  &lt;p&gt;在顺序一致性硬件上：不可以。&lt;br&gt;
  在 x86（或其他 TSO）架构上：不可以。&lt;br&gt;
  在 ARM&#x2F;POWER 架构上：可以！&lt;&#x2F;p&gt;
  &lt;p&gt;在使用普通变量的任何现代编译语言中：&lt;em&gt;可以！&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;正如上一篇文章中所述，我们假设每个例子都从所有共享变量初始化为零开始。名称 rN 表示类似寄存器或函数局部变量的私有存储；而其他诸如 x 和 y 的名称则是不同的共享（全局）变量。我们考察在执行结束时某种特定寄存器设置是否可能出现。在回答硬件的试金石测试时，我们假设线程中不会有编译器重新排序操作：列表中的指令会被直接翻译为处理器执行的汇编指令。&lt;&#x2F;p&gt;
&lt;p&gt;结果 r1 = 1，r2 = 0 对应于原程序中线程 2 完成其循环（此时 y 已更新）但随后打印了 0 的情况。这种结果不可能在任何顺序一致的程序操作交织模型中出现。对于汇编语言版本，打印 0 在 x86 上是不可能的，但在更宽松的架构如 ARM 和 POWER 上由于处理器自身的重排序优化则是可能的。在现代语言中，编译过程中的重排序使得无论底层硬件如何，这种结果都是可能出现的。&lt;&#x2F;p&gt;
&lt;p&gt;与其保证顺序一致性，正如我们之前提到的，现今的处理器保证了一种被称为“无数据竞争顺序一致性”（data-race-free sequential-consistency，简称 DRF-SC，有时也写作 SC-DRF）的属性。一个保证 DRF-SC 的系统必须定义特定的指令，称为同步指令（synchronizing instructions），它们为协调不同处理器（或线程）提供了一种方式。程序使用这些指令来建立在一个处理器上运行的代码与在另一个处理器上运行的代码之间的“先发生”（happens before）关系。&lt;&#x2F;p&gt;
&lt;p&gt;例如，下面展示了一个程序在两个线程上短暂执行的示意图；和往常一样，每个线程都假设运行在其专用的处理器上：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;mem-adve-4@2x.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;我们在上一篇文章中也看过这个程序。线程 1 和线程 2 都执行了一个同步指令 S(a)。在该程序的这个具体执行中，这两个 S(a) 指令建立了从线程 1 到线程 2 的“先发生”关系，因此线程 1 中的写操作 W(x) 发生在线程 2 中的读操作 R(x) 之前。&lt;&#x2F;p&gt;
&lt;p&gt;两个不同处理器上的事件如果不被“先发生”关系排序，可能会同时发生：具体的执行顺序是不确定的。我们称它们为并发执行。当对一个变量的写操作与对该变量的读操作或写操作并发执行时，就发生了数据竞争。提供 DRF-SC 的处理器（如今几乎所有处理器都提供）保证没有数据竞争的程序表现得就像运行在顺序一致的架构上一样。这是使得在现代处理器上编写正确多线程汇编程序成为可能的根本保证。&lt;&#x2F;p&gt;
&lt;p&gt;正如我们之前看到的，DRF-SC 也是现代语言所采纳的根本保证，目的是使得能够在高级语言中编写正确的多线程程序。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;compilers-and-optimizations&quot;&gt;Compilers and Optimizations&lt;a class=&quot;zola-anchor&quot; href=&quot;#compilers-and-optimizations&quot; aria-label=&quot;Anchor link for: compilers-and-optimizations&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;我们曾多次提到，编译器在生成最终可执行代码的过程中可能会对输入程序中的操作进行重新排序。让我们仔细看看这一说法，以及其他可能导致问题的优化。&lt;&#x2F;p&gt;
&lt;p&gt;普遍认为，编译器几乎可以任意地对普通的内存读写操作进行重新排序，只要这种重新排序不会改变单线程代码的观察执行结果。例如，考虑以下程序：&lt;&#x2F;p&gt;
&lt;div&gt;
    w = 1&lt;br&gt;
    x = 2&lt;br&gt;
    r1 = y&lt;br&gt;
    r2 = z
&lt;&#x2F;div&gt;
&lt;p&gt;由于 w、x、y 和 z 是四个不同的变量，这四条语句可以按编译器认为最合适的任何顺序执行。&lt;&#x2F;p&gt;
&lt;p&gt;如前所述，自由地重新排序读写操作的能力使得普通编译程序的保证至少和 ARM&#x2F;POWER 的松散内存模型一样弱，因为编译后的程序未能通过消息传递的试金石测试。实际上，编译程序的保证更为薄弱。&lt;&#x2F;p&gt;
&lt;p&gt;在硬件篇中，我们以一致性作为一个例子，说明了 ARM&#x2F;POWER 架构所保证的内容：&lt;&#x2F;p&gt;
&lt;div&gt;
    &lt;em&gt;litmus 测试：一致性&lt;&#x2F;em&gt;&lt;br&gt;
    这个程序能看到 r1 = 1, r2 = 2, r3 = 2, r4 = 1 吗？&lt;br&gt;
    （线程 3 在线程 4 看到相反结果之前看到 x = 1 而不是 x = 2 吗？）&lt;br&gt;&lt;br&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;&#x2F; 线程 1    &#x2F;&#x2F; 线程 2    &#x2F;&#x2F; 线程 3    &#x2F;&#x2F; 线程 4
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;x = 1       x = 2        r1 = x        r3 = x
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                         r2 = x        r4 = x
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;在顺序一致的硬件上：不。&amp;lt;br&amp;gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;在 x86（或其他 TSO）上：不。&amp;lt;br&amp;gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;在 ARM&#x2F;POWER 上：不。&amp;lt;br&amp;gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;在任何使用普通变量的现代编译语言中：&amp;lt;em&amp;gt;是的！&amp;lt;&#x2F;em&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;所有现代硬件都保证一致性，这也可以被视为对单个内存位置操作的顺序一致性。在这个程序中，两个写操作中必须有一个覆盖另一个，且整个系统必须就哪一个是哪个达成一致。结果是，由于编译时的程序重新排序，现代语言甚至都不提供一致性保证。&lt;&#x2F;p&gt;
&lt;p&gt;假设编译器重新排序了线程4中的两个读操作，然后指令按照以下交错顺序执行：&lt;&#x2F;p&gt;
&lt;div&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;&#x2F; Thread 1        &#x2F;&#x2F; Thread 2         &#x2F;&#x2F; Thread 3         &#x2F;&#x2F; Thread 4
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                                                            (reordered)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;(1) x = 1                              (2) r1 = x          (3) r4 = x
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;                    (4) x = 2          (5) r2 = x          (6) r3 = x
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;结果是 r1 = 1，r2 = 2，r3 = 2，r4 = 1，这在汇编程序中是不可能出现的，但在高级语言中却是可能的。从这个意义上讲，编程语言的内存模型都比最宽松的硬件内存模型更弱。&lt;&#x2F;p&gt;
&lt;p&gt;不过，仍然有一些保证。大家都同意需要提供 DRF-SC（数据竞争自由-顺序一致性），该保证禁止引入新的读写操作的优化，即使这些优化在单线程代码中是有效的。&lt;&#x2F;p&gt;
&lt;p&gt;例如，考虑以下代码：&lt;&#x2F;p&gt;
&lt;div style=&quot;font-family: monospace; white-space: pre;&quot;&gt;
if(c) {
    x++;
} else {
    ... lots of code ...
}
&lt;&#x2F;div&gt;
&lt;p&gt;有一个 if 语句，else 分支里有大量代码，而 if 分支里只有一个 x++。为了减少分支并且可能提高效率，可以考虑把 x++ 提前到 if 语句之前执行，然后如果判断错误，再在 else 里的大量代码中通过 x-- 来进行调整。也就是说，编译器可能会将这段代码重写成：&lt;&#x2F;p&gt;
&lt;div style=&quot;font-family: monospace; white-space: pre;&quot;&gt;
x++;
if(!c) {
    x--;
    ... lots of code ...
}
&lt;&#x2F;div&gt;
&lt;p&gt;这是安全的编译器优化吗？在单线程程序中，是的；但在多线程程序中，如果 x 被另一个线程共享且当 c 为 false 时，不安全：该优化会引入一个原本不存在的对 x 的竞态条件。&lt;&#x2F;p&gt;
&lt;p&gt;这个例子来源于 Hans Boehm 2004 年发表的论文&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.hpl.hp.com&#x2F;techreports&#x2F;2004&#x2F;HPL-2004-209.pdf&quot;&gt;《Threads Cannot Be Implemented As a Library》&lt;&#x2F;a&gt;，该论文论证了语言不能对多线程执行的语义保持沉默。&lt;&#x2F;p&gt;
&lt;p&gt;编程语言内存模型试图准确回答哪些优化是允许的，哪些是不允许的。通过回顾过去几十年来尝试建立这些模型的历史，我们可以了解哪些方法有效，哪些无效，并对未来的发展方向有所把握。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;original-java-memory-model-1996&quot;&gt;Original Java Memory Model (1996)&lt;a class=&quot;zola-anchor&quot; href=&quot;#original-java-memory-model-1996&quot; aria-label=&quot;Anchor link for: original-java-memory-model-1996&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Java 是第一个尝试明确写出对多线程程序保证的主流语言。它包含了互斥锁，并定义了它们所隐含的内存顺序要求。它还包括“volatile”原子变量：所有对volatile变量的读写都要求以程序顺序直接在主内存中执行，使得对volatile变量的操作能够以顺序一致的方式表现。最后，Java也指定（或至少尝试指定）了带有数据竞争的程序行为。其中一部分是强制规定普通变量的一种一致性形式，后文我们会进一步探讨。不幸的是，这一尝试在第一版Java语言规范（Java Language Specification (1996)）中存在至少两个严重缺陷。借助事后看来和我们已经设定的基础知识，这些缺陷很容易解释，当时则远不那么明显。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;atomics-need-to-synchronize-yuan-zi-cao-zuo-xu-yao-tong-bu&quot;&gt;Atomics need to synchronize(原子操作需要同步)&lt;a class=&quot;zola-anchor&quot; href=&quot;#atomics-need-to-synchronize-yuan-zi-cao-zuo-xu-yao-tong-bu&quot; aria-label=&quot;Anchor link for: atomics-need-to-synchronize-yuan-zi-cao-zuo-xu-yao-tong-bu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;第一个缺陷是volatile原子变量是非同步的，因此它们无法帮助消除程序其余部分的竞态条件。我们之前看到的Java版本的消息传递程序就是一个例子：&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;
int x;
volatile int done;

&#x2F;&#x2F; Thread 1                &#x2F;&#x2F; Thread 2
x = 42;                    while(done == 0) { &#x2F;* loop *&#x2F; }
done = 1;                  print(x);
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;因为 done 被声明为 volatile，循环被保证会结束：编译器不能将其缓存到寄存器中以避免导致无限循环。然而，程序不能保证一定会打印出 1。编译器并没有被禁止重新排序对 x 和 done 的访问，硬件也没有被要求禁止做同样的事情。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;编译器在优化代码时，可能会调整（重新排序）对变量 x 和 done 的访问顺序，以提高性能。这种重新排序是在程序语义允许的范围内进行的，但并没有被明确禁止。换句话说，编译器可能先执行对 done 的赋值，再执行对 x 的写入，或者把读取 done 的操作提前，这样就可能打乱原本代码中变量访问的顺序。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;由于 Java 中的 volatile 是非同步的原子操作，无法用它们来构建新的同步原语。从这个意义上说，最初的 Java 内存模型太弱了。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;coherence-is-incompatible-with-compiler-optimizations-yi-zhi-xing-yu-bian-yi-qi-you-hua-bu-jian-rong&quot;&gt;Coherence is incompatible with compiler optimizations(一致性与编译器优化不兼容)&lt;a class=&quot;zola-anchor&quot; href=&quot;#coherence-is-incompatible-with-compiler-optimizations-yi-zhi-xing-yu-bian-yi-qi-you-hua-bu-jian-rong&quot; aria-label=&quot;Anchor link for: coherence-is-incompatible-with-compiler-optimizations-yi-zhi-xing-yu-bian-yi-qi-you-hua-bu-jian-rong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;最初的 Java 内存模型过于严格：要求一致性——一旦线程读取了内存位置的新值，就不能再读到旧值——这禁止了基本的编译器优化。我们之前已经讨论过，重排序读取操作会破坏一致性，但你可能会想，好吧，不要重排序读取操作。这里有一种更微妙的方式，一致性可能会被另一种优化手段破坏：常见的公共子表达式消除。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;公共子表达式（Common Subexpression）是指在代码中多次出现且具有相同值的表达式。&lt;br&gt;
int a = b + c;&lt;br&gt;
int d = b + c;  &#x2F;&#x2F; 这里的 b + c 就是一个公共子表达式
因为 b + c 在两个地方都出现了，编译器可以做“公共子表达式消除”优化：只计算一次 b + c，然后重复使用这个结果，避免重复计算，从而提高程序效率。&lt;br&gt;
但是在涉及多线程和内存模型时，如果某个表达式的值可能被其他线程修改，进行公共子表达式消除可能导致程序读取过时的值，破坏数据一致性。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;考虑这个Java程序：&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;&#x2F;&#x2F; p and q may or may not point at the same object.
int i = p.x;
&#x2F;&#x2F; ... maybe another thread writes p.x at this point ...
int j = q.x;
int k = p.x;
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在这个程序中，公共子表达式消除会注意到 p.x 被计算了两次，并将最后一行优化为 k = i。但是如果 p 和 q 指向同一个对象，并且另一个线程在读取 i 和 j 之间写入了 p.x，那么复用旧值 i 赋给 k 会违反一致性：读取 i 时看到的是旧值，读取 j 时看到的是新值，但读取 k 时复用 i 又会看到旧值。不能优化掉冗余的读取会限制大多数编译器，使生成的代码变慢。&lt;&#x2F;p&gt;
&lt;p&gt;硬件比编译器更容易提供一致性，因为硬件可以应用动态优化：它可以根据给定内存读写序列中涉及的具体地址调整优化路径。相比之下，编译器只能应用静态优化：它们必须提前生成一段无论涉及哪些地址和值都能正确执行的指令序列。举例来说，编译器很难根据 p 和 q 是否指向同一个对象来改变行为，至少不写出针对两种情况的代码，否则会带来显著的时间和空间开销。编译器对于内存位置之间可能存在的别名情况缺乏完整的知识，这意味着真正实现一致性需要放弃一些基本的优化。&lt;&#x2F;p&gt;
&lt;p&gt;比尔·帕格（Bill Pugh）在他1999年的论文&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;citeseerx.ist.psu.edu&#x2F;viewdoc&#x2F;download?doi=10.1.1.17.7914&amp;amp;rep=rep1&amp;amp;type=pdf&quot;&gt;《修复Java内存模型》（Fixing the Java Memory Model）&lt;&#x2F;a&gt;中指出了这个问题和其他问题。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;new-java-memory-model-2004&quot;&gt;New Java Memory Model (2004)&lt;a class=&quot;zola-anchor&quot; href=&quot;#new-java-memory-model-2004&quot; aria-label=&quot;Anchor link for: new-java-memory-model-2004&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;由于这些问题，并且因为最初的 Java 内存模型即使对专家来说也难以理解，Pugh 等人开始努力为 Java 定义一个新的内存模型。该模型成为 ISR-133，并被采纳在 2004 年发布的 Java 5.0 中。其权威参考是 Jeremy Manson、Bill Pugh 和 Sarita Adve 在 2005 年发表的“&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;rsim.cs.uiuc.edu&#x2F;Pubs&#x2F;popl05.pdf&quot;&gt;The Java Memory Model&lt;&#x2F;a&gt;”一文，以及 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;drum.lib.umd.edu&#x2F;bitstream&#x2F;handle&#x2F;1903&#x2F;1949&#x2F;umi-umd-1898.pdf;jsessionid=4A616CD05E44EA7D47B6CF4A91B6F70D?sequence=1&quot;&gt;Manson 的博士论文&lt;&#x2F;a&gt;中提供的更多细节。新模型采用了 DRF-SC（数据竞争自由-顺序一致）方法：保证无数据竞争的 Java 程序将以顺序一致的方式执行。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;synchronizing-atomics-and-other-operations-tong-bu-yuan-zi-cao-zuo-he-qi-ta-cao-zuo&quot;&gt;Synchronizing atomics and other operations(同步原子操作和其他操作)&lt;a class=&quot;zola-anchor&quot; href=&quot;#synchronizing-atomics-and-other-operations-tong-bu-yuan-zi-cao-zuo-he-qi-ta-cao-zuo&quot; aria-label=&quot;Anchor link for: synchronizing-atomics-and-other-operations-tong-bu-yuan-zi-cao-zuo-he-qi-ta-cao-zuo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;如前所述，为了编写无数据竞争的程序，程序员需要使用同步操作来建立“先发生关系”，以确保一个线程不会在另一个线程读取或写入非原子变量的同时写入该变量。在 Java 中，主要的同步操作有：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;线程的创建发生在该线程的第一个动作之前。&lt;&#x2F;li&gt;
&lt;li&gt;互斥锁 m 的释放发生在随后对 m 的任何加锁之前。&lt;&#x2F;li&gt;
&lt;li&gt;对 volatile 变量 v 的写操作发生在随后对 v 的任何读操作之前。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;“随后（subsequent）”是什么意思？Java 定义所有锁操作、解锁操作和 volatile 变量访问的行为，就好像它们按某种顺序进行顺序一致的交错执行，从而在整个程序中为这些操作定义了一个总顺序。“随后”意味着在该总顺序中较晚发生。也就是说，锁、解锁和 volatile 变量访问的总体顺序定义了“随后”的含义，然后“随后”定义了由特定执行创建的“先发生”边，从而“先发生”边决定了该执行是否存在数据竞争。如果不存在数据竞争，那么执行就表现为顺序一致的方式。&lt;&#x2F;p&gt;
&lt;p&gt;volatile 访问必须表现得像在某种总顺序中执行，这一事实意味着在&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;hwmm#x86&quot;&gt;存储缓冲试金石（store buffer litmus test）&lt;&#x2F;a&gt;中，不可能出现 r1 = 0 和 r2 = 0 的情况。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Litmus Test: Store Buffering&lt;&#x2F;em&gt;&lt;br &#x2F;&gt;
这个程序是否可能看到结果 r1 = 0, r2 = 0？&lt;&#x2F;p&gt;
&lt;pre&gt;
&#x2F;&#x2F; 线程 1                     &#x2F;&#x2F; 线程 2
x = 1;                       y = 1;
r1 = y;                      r2 = x;
&lt;&#x2F;pre&gt;
&lt;p&gt;在顺序一致的硬件上：否。&lt;br &#x2F;&gt;
在 x86（或其他 TSO）架构上：是！&lt;br &#x2F;&gt;
在 ARM&#x2F;POWER 架构上：是！&lt;br &#x2F;&gt;
在使用 volatile 的 Java 中：否。&lt;&#x2F;p&gt;
&lt;p&gt;在 Java 中，对于 volatile 变量 x 和 y，读写操作不能被重排序：必须先有一个写操作，接着的读操作必须看到第一个写操作的结果。如果没有顺序一致性的要求，比如说，volatile 变量只是要求保持一致性，那么这两次读操作可能会读不到写操作的结果。&lt;&#x2F;p&gt;
&lt;p&gt;这里有一个重要但微妙的点：所有同步操作的总顺序是与“先发生”关系分开的。并非在程序中每个锁、解锁或 volatile 变量访问之间都存在单向的“先发生”边；你只能从某次写操作到观察该写操作的读操作之间获得“先发生”边。例如，不同互斥锁之间没有“先发生”边，不同变量的 volatile 访问之间也没有“先发生”边，尽管整体上这些操作必须表现得像是单一的顺序一致的交错执行。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;semantics-for-racy-programs-jing-tai-cheng-xu-de-yu-yi&quot;&gt;Semantics for racy programs(竞态程序的语义)&lt;a class=&quot;zola-anchor&quot; href=&quot;#semantics-for-racy-programs-jing-tai-cheng-xu-de-yu-yi&quot; aria-label=&quot;Anchor link for: semantics-for-racy-programs-jing-tai-cheng-xu-de-yu-yi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;DRF-SC（数据竞争自由-顺序一致性）只保证对没有数据竞争的程序表现出顺序一致的行为。新的 Java 内存模型，像原始模型一样，出于多种原因定义了竞态程序的行为：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;支持 Java 的通用安全性和安全保证。&lt;&#x2F;li&gt;
&lt;li&gt;让程序员更容易发现错误。&lt;&#x2F;li&gt;
&lt;li&gt;使攻击者更难利用问题，因为竞态导致的潜在损害更有限。&lt;&#x2F;li&gt;
&lt;li&gt;让程序员更清楚他们的程序在做什么。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;新的模型并没有依赖一致性，而是重用了“先发生”关系（该关系已用于判断程序是否存在数据竞争）来决定竞态读写的结果。&lt;&#x2F;p&gt;
&lt;p&gt;Java 的具体规则是，对于字长大小或更小的变量，变量（或字段）x 的一次读取必须看到某个对 x 的单一写操作所存储的值。如果写操作 w 不在读操作 r 之前发生，那么读 r 可以观察写操作 w。也就是说，r 可以观察在 r 之前发生的写操作（但这些写操作不会在 r 之前被覆盖），并且它也可以观察与 r 存在竞争的写操作。&lt;&#x2F;p&gt;
&lt;p&gt;以这种方式使用“先发生”关系，结合能够建立新的“先发生”边的同步原子操作（volatile），相较于原始的 Java 内存模型是一个重大改进。它为程序员提供了更有用的保证，并且使许多重要的编译器优化成为可能。这仍然是今天 Java 的内存模型。然而，这个模型仍不是完全正确：使用“先发生”关系定义竞态程序语义时，仍存在一些问题。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;happens-before-does-not-rule-out-incoherence-xian-fa-sheng-happens-before-guan-xi-bing-bu-pai-chu-bu-yi-zhi-xing&quot;&gt;Happens-before does not rule out incoherence(“先发生（happens-before）关系并不排除不一致性)&lt;a class=&quot;zola-anchor&quot; href=&quot;#happens-before-does-not-rule-out-incoherence-xian-fa-sheng-happens-before-guan-xi-bing-bu-pai-chu-bu-yi-zhi-xing&quot; aria-label=&quot;Anchor link for: happens-before-does-not-rule-out-incoherence-xian-fa-sheng-happens-before-guan-xi-bing-bu-pai-chu-bu-yi-zhi-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;使用先发生关系来定义程序语义的第一个问题与一致性有关（真的！）。以下示例摘自 Jaroslav Ševčík 和 David Aspinall 的论文&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;citeseerx.ist.psu.edu&#x2F;viewdoc&#x2F;download?doi=10.1.1.112.1790&amp;amp;rep=rep1&amp;amp;type=pdf&quot;&gt;《On the Validity of Program Transformations in the Java Memory Model》&lt;&#x2F;a&gt;（2007 年）。&lt;&#x2F;p&gt;
&lt;p&gt;下面是一个包含三个线程的程序。假设线程 1 和线程 2 已知将在线程 3 开始之前执行完毕。&lt;&#x2F;p&gt;
&lt;pre&gt;

&#x2F;&#x2F; Thread 1          &#x2F;&#x2F; Thread 2          &#x2F;&#x2F; Thread 3
lock(m1)             lock(m2)
x = 1                x = 2
unlock(m1)           unlock(m2)

                                          lock(m1)
                                          lock(m2)
                                          r1 = x
                                          r2 = x
                                          unlock(m2)
                                          unlock(m1)
&lt;&#x2F;pre&gt;
&lt;p&gt;线程1在持有互斥锁m1时写入x = 1，线程2在持有互斥锁m2时写入x = 2。这是不同的互斥锁，因此这两个写操作存在竞态。然而，只有线程3读取x，而且是在获取了两个互斥锁之后执行读取的。读入r1的值可以是任意一个写入的值：因为这两个写操作都发生在读之前，且彼此之间没有明确的覆盖关系。按同样的道理，读入r2的值也可以是任意一个写入的值。但严格来说，Java内存模型并没有规定这两个读操作的结果必须一致：在技术上讲，r1和r2可能读取到不同的x的值。也就是说，这个程序运行结束时，r1和r2可能持有不同的值。当然，实际实现不会产生不同的r1和r2值。互斥排除意味着两个读操作之间不会有写操作发生，它们必须得到相同的值。但内存模型允许不同的读结果，这说明它在某种技术层面上没有精确描述真实的Java实现。&lt;&#x2F;p&gt;
&lt;p&gt;情况变得更糟。如果我们在两个读操作之间加入一条运算指令， x = r1，情况如下：&lt;&#x2F;p&gt;
&lt;pre&gt;
&#x2F;&#x2F; Thread 1           &#x2F;&#x2F; Thread 2           &#x2F;&#x2F; Thread 3
lock(m1)              lock(m2)
x = 1                 x = 2
unlock(m1)            unlock(m2)
                                            lock(m1)
                                            lock(m2)
                                            r1 = x
                                            x = r1   &#x2F;&#x2F; !?
                                            r2 = x
                                            unlock(m2)
                                            unlock(m1)
&lt;&#x2F;pre&gt;
&lt;p&gt;现在，很明显，r2 = x 的读取必须使用r1赋值给x的结果，因此程序中r1和r2的值必须相同。两个值r1和r2现在被保证是相等的。&lt;&#x2F;p&gt;
&lt;p&gt;这两个程序之间的区别带来了编译器的问题。一个编译器看到r1 = x后紧跟x = r1，可能会想删除第二个赋值，因为它看起来“明显”是多余的。但这样做的“优化”改变了第二个程序的行为，第二个程序必须保证r1和r2的值相同，而第一个程序在技术上可以允许r1和r2不同。因此，根据Java内存模型，这种优化在技术上是无效的：它改变了程序的语义。需要明确的是，这种优化不会改变任何真实的JVM上执行的Java程序的语义。但奇怪的是，Java内存模型不允许这种优化，说明这里还有更多需要说明的内容。&lt;&#x2F;p&gt;
&lt;p&gt;关于这个例子和更多相关讨论，可以参考Ševčík和Aspinall的论文。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;happens-before-does-not-rule-out-acausality-xian-xing-fa-sheng-guan-xi-happens-before-bing-bu-pai-chu-fei-yin-guo-xing&quot;&gt;Happens-before does not rule out acausality(“先行发生关系（happens-before）并不排除非因果性)&lt;a class=&quot;zola-anchor&quot; href=&quot;#happens-before-does-not-rule-out-acausality-xian-xing-fa-sheng-guan-xi-happens-before-bing-bu-pai-chu-fei-yin-guo-xing&quot; aria-label=&quot;Anchor link for: happens-before-does-not-rule-out-acausality-xian-xing-fa-sheng-guan-xi-happens-before-bing-bu-pai-chu-fei-yin-guo-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;上一个例子被证明是个简单的问题。这里有一个更难的问题。考虑这个试金石测试，使用普通的（非volatile）Java变量：”&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Litmus 测试：无因缘竞争值&lt;&#x2F;em&gt;&lt;br&gt;
这个程序能看到 r1 = 42，r2 = 42 吗？&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;
&#x2F;&#x2F; 线程 1                    &#x2F;&#x2F; 线程 2
r1 = x                       r2 = y
y = r1                       x = r2
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;（显然不可能！）&lt;&#x2F;p&gt;
&lt;p&gt;所有变量在这个程序一开始都被初始化为零，和往常一样，然后这个程序实际上在一个线程中运行 y = x，而在另一个线程中运行 x = y。x 和 y 可能最终会变成 42 吗？在现实生活中，显然不会。但为什么呢？内存模型实际上并不禁止这种结果。&lt;&#x2F;p&gt;
&lt;p&gt;假设“r1 = x”确实读到了42。然后“y = r1”会将42写入y，接着竞争的“r2 = y”可能读到42，导致“x = r2”写入42到x。这次写入和原始的“r1 = x”存在数据竞争（因此可被观察到），看起来好像为最初的假设提供了合理的依据。在这个例子中，42被称为“无因缘值”，因为它没有任何合理的来源，却通过循环逻辑自我证明了合理性。假如内存之前存储过42，在当前为0之前，硬件错误地推测它仍然是42，会怎样？这种猜测可能变成自我实现的预言。（这个论点在“&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;spectreattack.com&#x2F;&quot;&gt;光谱及相关攻击&lt;&#x2F;a&gt;”之前显得更牵强，说明了硬件推测的激进程度。即便如此，没有硬件会以这种方式产生无因缘值。）&lt;&#x2F;p&gt;
&lt;p&gt;很明显，这个程序不可能以 r1 和 r2 都设置为 42 结束，但“先发生关系”（happens-before）本身并不能解释为什么这不可能发生。这再次表明存在某种不完备性。新的 Java 内存模型花了大量时间来解决这种不完备性，稍后会详细介绍。&lt;&#x2F;p&gt;
&lt;p&gt;这个程序存在数据竞争——对 x 和 y 的读取与另一个线程中的写入竞争——因此我们可能会回到争论这是一个不正确的程序。但这里有一个无数据竞争（data-race-free）的版本：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;试金石测试：无数据竞争的无因缘值&lt;&#x2F;em&gt;&lt;br&gt;
这个程序能看到 r1 = 42，r2 = 42 吗？&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;
&#x2F;&#x2F; 线程 1                    &#x2F;&#x2F; 线程 2
r1 = x                       r2 = y
if (r1 == 42)                if (r2 == 42)
    y = r1                     x = r2
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;（显然不可能！）&lt;&#x2F;p&gt;
&lt;p&gt;由于 x 和 y 起始都是零，任何顺序一致的执行都不会执行写操作，因此这个程序没有写操作，也就没有竞争。不过，再次强调，仅靠“先发生关系”并不能排除这样的可能性：假设 r1 = x 读取了那个竞争的、尚未完成的写操作，然后基于这个假设，使得条件都成立，最终 x 和 y 都是 42。这是另一种无因缘值，但这次是在没有数据竞争的程序中。任何保证无数据竞争的模型（DRF-SC）必须保证这个程序最终只能看到全零值，但“先发生关系”仍然无法解释为什么如此。&lt;&#x2F;p&gt;
&lt;p&gt;Java 内存模型花了大量篇幅来尝试排除这些无因果关系的假设性情况，我这里就不展开讲了。不幸的是，五年后，Sarita Adve 和 Hans Boehm 对这项工作有如下评价：&lt;&#x2F;p&gt;
&lt;p&gt;禁止这类因果违例，同时又不禁止其他期望的优化，结果证明出乎意料的困难……经过多次提案和五年的激烈讨论，当前模型被认为是最佳折中方案……不幸的是，这个模型非常复杂，已知存在一些令人惊讶的行为，最近还被发现有一个漏洞。&lt;&#x2F;p&gt;
&lt;p&gt;（Adve 和 Boehm，&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;cacm.acm.org&#x2F;magazines&#x2F;2010&#x2F;8&#x2F;96610-memory-models-a-case-for-rethinking-parallel-languages-and-hardware&#x2F;fulltext&quot;&gt;《内存模型：重新思考并行语言与硬件的案例》&lt;&#x2F;a&gt;，2010年8月）&lt;&#x2F;p&gt;
&lt;h2 id=&quot;c-11-memory-model-2011&quot;&gt;C++11 Memory Model (2011)&lt;a class=&quot;zola-anchor&quot; href=&quot;#c-11-memory-model-2011&quot; aria-label=&quot;Anchor link for: c-11-memory-model-2011&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;我们先暂时搁置 Java，来看看 C++。受 Java 新内存模型明显成功的启发，许多相同的人着手为 C++ 定义一个类似的内存模型，最终被采纳进了 C++11。与 Java 相比，C++ 在两个重要方面有所不同。首先，C++ 对存在数据竞争的程序不做任何保证，这似乎消除了对 Java 模型复杂性的许多需求。其次，C++ 提供了三种类型的原子操作：强同步（“sequentially consistent”, 顺序一致），弱同步（“acquire&#x2F;release”，仅保证一致性），以及无同步（“relaxed”，用于隐藏数据竞争）。放松的原子操作重新引入了所有关于定义“多少算是数据竞争程序”这一意义上的复杂性。结果是，C++ 模型比 Java 的还要复杂，且对程序员的帮助更少。&lt;&#x2F;p&gt;
&lt;p&gt;C++11 还定义了原子栅栏（atomic fences）作为原子变量的替代方案，但它们使用得不如原子变量普遍，这里我也不打算展开讨论。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;drf-sc-or-catch-fire&quot;&gt;DRF-SC or Catch Fire&lt;a class=&quot;zola-anchor&quot; href=&quot;#drf-sc-or-catch-fire&quot; aria-label=&quot;Anchor link for: drf-sc-or-catch-fire&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;与 Java 不同，C++ 对数据竞争的程序不提供任何保证。任何包含数据竞争的程序一旦发生竞争访问，就会陷入“未定义行为”。程序执行的最初几微秒内允许发生竞争访问，这可能导致程序行为任意错误，几小时或几天后才表现出来。这种现象通常称为“DRF-SC 或灾难性错误”：如果程序没有数据竞争，它会以顺序一致的方式运行；如果有数据竞争，它的行为则完全不可预测，可能会出现灾难性错误。&lt;&#x2F;p&gt;
&lt;p&gt;关于 DRF-SC 或灾难性错误的详细论述，请参见 Boehm 的&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;open-std.org&#x2F;jtc1&#x2F;sc22&#x2F;wg21&#x2F;docs&#x2F;papers&#x2F;2007&#x2F;n2176.html#undefined&quot;&gt;《Memory Model Rationales》&lt;&#x2F;a&gt;（2007 年）以及 Boehm 和 Adve 的&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.hpl.hp.com&#x2F;techreports&#x2F;2008&#x2F;HPL-2008-56.pdf&quot;&gt;《Foundations of the C++ Concurrency Memory Model》&lt;&#x2F;a&gt;（2008 年）。&lt;&#x2F;p&gt;
&lt;p&gt;简要来说，这一立场有四个常见的理由：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;C 和 C++ 本身就充满了未定义行为，语言中有部分角落编译器优化极为激进，用户最好不要触及，否则会有严重后果。再多一个未定义行为又有什么坏处呢？&lt;&#x2F;li&gt;
&lt;li&gt;现有的编译器和库编写时根本不考虑线程问题，任意方式打破竞争程序。要找到并修复所有问题几乎不可能，虽然仍不清楚这些未修复的编译器和库如何应对放宽的原子操作。&lt;&#x2F;li&gt;
&lt;li&gt;真正懂得自己在做什么并想避免未定义行为的程序员可以使用放宽的原子操作。&lt;&#x2F;li&gt;
&lt;li&gt;将竞态语义定义为未定义允许实现检测和诊断竞态问题并停止执行。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;个人认为，最后一个理由是最有说服力的，虽然我也注意到可以说“允许竞态检测器”而不说“对整数的竞态可能会使整个程序失效”。&lt;&#x2F;p&gt;
&lt;p&gt;这里是一个来自《Memory Model Rationales》的例子，我认为它很好地体现了 C++ 方法的本质以及相关问题。请考虑这个程序，它引用了一个全局变量 x。&lt;&#x2F;p&gt;
&lt;pre&gt;
    unsigned i = x;

    if (i &lt; 2) {
        foo: ...
        switch (i) {
        case 0:
            ...;
            break;
        case 1:
            ...;
            break;
        }
    }
&lt;&#x2F;pre&gt;
&lt;p&gt;这个说法是，C++ 编译器可能会将变量 i 保存在寄存器中，但如果 foo 标签处的代码比较复杂，可能需要重新使用这些寄存器。编译器可能不会将当前 i 的值保存到函数栈上，而是在到达 switch 语句时再次从全局变量 x 重新加载 i。结果是，在 if 语句体执行到一半时，i &amp;lt; 2 的条件可能不再成立。如果编译器做了类似将 switch 编译成基于 i 索引的计算跳转表的操作，代码可能会索引到表的末尾以外的位置，并跳转到一个意外的地址，这可能导致任意严重的错误。&lt;&#x2F;p&gt;
&lt;p&gt;基于这个例子及类似情况，C++ 内存模型的作者们得出结论：任何数据竞争访问都必须被允许，以致可能对程序未来的执行造成无限制的损害。就个人而言，我认为在多线程程序中，编译器不应假设它们可以通过重新执行初始化该变量的内存读操作来重新加载局部变量 i。期待为单线程环境编写的现有 C++ 编译器能够发现并修复类似的代码生成问题可能是不切实际的，但对于新语言，我认为我们应当设定更高的目标。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;digression-undefined-behavior-in-c-and-c-ti-wai-hua-c-he-c-zhong-de-wei-ding-yi-xing-wei&quot;&gt;Digression: Undefined behavior in C and C++(题外话： C 和 C++ 中的未定义行为)&lt;a class=&quot;zola-anchor&quot; href=&quot;#digression-undefined-behavior-in-c-and-c-ti-wai-hua-c-he-c-zhong-de-wei-ding-yi-xing-wei&quot; aria-label=&quot;Anchor link for: digression-undefined-behavior-in-c-and-c-ti-wai-hua-c-he-c-zhong-de-wei-ding-yi-xing-wei&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;顺便提一句，C 和 C++ 坚持认为编译器可以因程序中的错误而表现出任意糟糕的行为，这导致了一些非常荒谬的结果。例如，考虑这个程序，它曾在 2017 年成为 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;andywingo&#x2F;status&#x2F;903577501745770496&quot;&gt;Twitter 上的一个讨论话题&lt;&#x2F;a&gt;：&lt;&#x2F;p&gt;
&lt;pre&gt;
    #include &lt;cstdlib&gt;

    typedef int (*Function)();

    static Function Do;

    static int EraseAll() {
        return system(&quot;rm -rf slash&quot;);
    }

    void NeverCalled() {
        Do = EraseAll;
    }

    int main() {
        return Do();
    }
&lt;&#x2F;pre&gt;
&lt;p&gt;如果你是像 Clang 这样的现代 C++ 编译器，你可能会这样理解这个程序：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;在 main 中，显然 Do 要么是 null，要么是 EraseAll。&lt;&#x2F;li&gt;
&lt;li&gt;如果 Do 是 EraseAll，那么调用 Do() 就相当于调用 EraseAll()。&lt;&#x2F;li&gt;
&lt;li&gt;如果 Do 是 null，那么调用 Do() 是未定义行为，我可以以任何想要的方式实现它，包括无条件地调用 EraseAll()。&lt;&#x2F;li&gt;
&lt;li&gt;因此，我可以将间接调用 Do() 优化为直接调用 EraseAll()。&lt;&#x2F;li&gt;
&lt;li&gt;既然如此，我还可以顺便内联 EraseAll()。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;最终结果是，Clang 将程序优化为&lt;&#x2F;p&gt;
&lt;pre&gt;
    int main() {
        return system(&quot;rm -rf slash&quot;);
    }
&lt;&#x2F;pre&gt;
&lt;p&gt;你不得不承认：与这个例子相比，局部变量 i 在 if (i &amp;lt; 2) 语句体执行到一半时突然不再小于 2 的可能性看起来并不奇怪。&lt;&#x2F;p&gt;
&lt;p&gt;本质上，现代 C 和 C++ 编译器假设没有程序员会敢于尝试未定义行为。一个程序员竟然会写出有漏洞的程序？这是难以想象的！&lt;&#x2F;p&gt;
&lt;p&gt;正如我所说，在新语言中，我认为我们应当设定更高的目标。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;acquire-release-atomics&quot;&gt;Acquire&#x2F;release atomics&lt;a class=&quot;zola-anchor&quot; href=&quot;#acquire-release-atomics&quot; aria-label=&quot;Anchor link for: acquire-release-atomics&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;C++ 采用了顺序一致性的原子变量，这与（新）Java中的 volatile 变量非常相似（但与 C++ 的 volatile 无关）。在我们的消息传递示例中，我们可以将 done 声明为：&lt;&#x2F;p&gt;
&lt;pre&gt;
    atomic&lt;int&gt; done;
&lt;&#x2F;pre&gt;
&lt;p&gt;然后像使用 Java 中的普通变量一样使用 done。或者，我们可以声明一个普通的 int done；然后使用&lt;&#x2F;p&gt;
&lt;pre&gt;
    atomic_store(&amp;done, 1);
&lt;&#x2F;pre&gt;
&lt;p&gt;和&lt;&#x2F;p&gt;
&lt;pre&gt;
    while(atomic_load(&amp;done) == 0) { &#x2F;* loop *&#x2F; }
&lt;&#x2F;pre&gt;
&lt;p&gt;来访问它。无论采用哪种方式，对 done 的操作都会参与原子操作的顺序一致的总顺序，并同步程序的其他部分。&lt;&#x2F;p&gt;
&lt;p&gt;C++ 还引入了更弱的原子操作，可以使用 atomic_store_explicit 和 atomic_load_explicit 进行访问，并带有额外的内存顺序参数。使用 memory_order_seq_cst 会使这些显式调用等同于上面较简短的调用。&lt;&#x2F;p&gt;
&lt;p&gt;这些较弱的原子操作称为 acquire&#x2F;release 原子操作，其中后续的 acquire 观察到的 release 会在发布到获取之间建立一个先行关系（happens-before）。这个术语旨在类比互斥锁：release 就像解锁互斥锁，acquire 就像加锁同一个互斥锁。发布之前执行的写操作必须对之后获取后执行的读操作可见，就像解锁互斥锁之前执行的写操作必须对之后加锁同一个互斥锁后的读操作可见一样。&lt;&#x2F;p&gt;
&lt;p&gt;要使用较弱的原子，我们可以更改我们的消息示例&lt;&#x2F;p&gt;
&lt;pre&gt;
    atomic_store(&amp;done, 1, memory_order_release);
&lt;&#x2F;pre&gt;
&lt;p&gt;和&lt;&#x2F;p&gt;
&lt;pre&gt;
    while(atomic_load(&amp;done, memory_order_acquire) == 0) { &#x2F;* loop *&#x2F; }
&lt;&#x2F;pre&gt;
&lt;p&gt;它仍然是正确的。但并非所有程序都会这样。&lt;&#x2F;p&gt;
&lt;p&gt;回想一下，顺序一致性的原子操作要求程序中所有原子操作的行为与某种全局交错（即执行的全序）保持一致。而 acquire&#x2F;release 原子操作则不要求这一点。它们只要求对单个内存位置的操作具备顺序一致的交错关系，也就是说，它们只要求具有一致性（coherence）。其结果是，使用多个内存位置的 acquire&#x2F;release 原子操作的程序，可能观测到的执行顺序无法通过程序中所有 acquire&#x2F;release 原子操作的顺序一致交错来解释，这可以说是对数据竞争自由（DRF-SC）原则的违反！&lt;&#x2F;p&gt;
&lt;p&gt;为了说明两者的区别，下面再以存储缓冲区为例：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Litmus 测试：存储缓冲&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;该程序能否观察到 r1 = 0，r2 = 0？&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;
&#x2F;&#x2F; 线程 1                  &#x2F;&#x2F; 线程 2
x = 1                      y = 1
r1 = y                     r2 = x
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在顺序一致性硬件上：不可能。&lt;&#x2F;p&gt;
&lt;p&gt;在 x86（或其他 TSO）上：&lt;strong&gt;可能！&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;在 ARM&#x2F;POWER 上：&lt;strong&gt;可能！&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;在 Java（使用 volatile）上：不可能。&lt;&#x2F;p&gt;
&lt;p&gt;在 C++11（顺序一致性原子操作）上：不可能。&lt;&#x2F;p&gt;
&lt;p&gt;在 C++11（acquire&#x2F;release 原子操作）上：&lt;strong&gt;可能！&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;C++ 的顺序一致性原子操作与 Java 的 volatile 变量相匹配。但 acquire-release 原子操作在 x 和 y 的顺序之间没有任何关系。具体来说，程序允许表现为“r1 = y 发生在 y = 1 之前”的同时，“r2 = x 发生在 x = 1 之前”，这导致 r1 = 0，r2 = 0，违背了整个程序的顺序一致性。这种现象可能仅仅因为它们在 x86 架构上是被允许的。&lt;&#x2F;p&gt;
&lt;p&gt;需要注意的是，对于一组特定的读取观察到特定写入的情况，C++ 的顺序一致性原子操作和 C++ 的 acquire&#x2F;release 原子操作会创建相同的先行关系（happens-before 边）。它们之间的区别在于，对于某些特定的读取观察到特定写入的集合，顺序一致性原子操作是不允许的，而 acquire&#x2F;release 原子操作则允许。一个例子是导致 r1 = 0，r2 = 0 发生的存储缓冲情形。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-real-example-of-the-weakness-of-acquire-release&quot;&gt;A real example of the weakness of acquire&#x2F;release&lt;a class=&quot;zola-anchor&quot; href=&quot;#a-real-example-of-the-weakness-of-acquire-release&quot; aria-label=&quot;Anchor link for: a-real-example-of-the-weakness-of-acquire-release&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;Acquire&#x2F;release 原子操作在实际应用中不如提供顺序一致性的原子操作那么有用。举个例子，假设我们有一个新的同步原语，一个只使用一次的条件变量，它有两个方法 Notify 和 Wait。为了简化起见，只有一个线程会调用 Notify，只有一个线程会调用 Wait。我们希望在另一个线程还未等待时，使 Notify 实现无锁（lock-free）。我们可以用一对原子整数来实现这一点：&lt;&#x2F;p&gt;
&lt;pre&gt;
        class Cond {
            atomic&lt;int&gt; done;
            atomic&lt;int&gt; waiting;
            ...
        };

        void Cond::notify() {
            done = 1;
            if (!waiting)
                return;
            &#x2F;&#x2F; ... wake up waiter ...
        }

        void Cond::wait() {
            waiting = 1;
            if(done)
                return;
            &#x2F;&#x2F; ... sleep ...
        }
&lt;&#x2F;pre&gt;
&lt;p&gt;这段代码的重要部分在于，notify 在检查 waiting 之前先设置 done，而 wait 在检查 done 之前先设置 waiting，这样 concurrent 调用 notify 和 wait 就不会导致 notify 立即返回而 wait 进入睡眠状态。但使用 C++ 的 acquire&#x2F;release 原子操作时，这种情况是可能发生的。而且它们可能只偶尔出现，使这个错误很难重现和诊断。（更糟的是，在某些架构上，如 64 位 ARM，实现 acquire&#x2F;release 原子操作的最佳方式是作为顺序一致性原子操作，因此你可能会写出在 64 位 ARM 上运行正常的代码，但在移植到其他系统时才发现它是错误的。）&lt;&#x2F;p&gt;
&lt;p&gt;基于这种理解，“acquire&#x2F;release”对这些原子操作来说是一个不幸的名字，因为顺序一致性原子操作做了同样多的获取和释放操作。不同之处在于丢失了顺序一致性。也许把它们称为“coherence”（一致性）原子操作会更好。但为时已晚。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;relaxed-atomics&quot;&gt;Relaxed atomics&lt;a class=&quot;zola-anchor&quot; href=&quot;#relaxed-atomics&quot; aria-label=&quot;Anchor link for: relaxed-atomics&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;C++ 不仅仅停留在具有一致性的 acquire&#x2F;release 原子操作上，还引入了非同步原子的 relaxed 原子操作（memory_order_relaxed）。这些原子操作完全没有同步效果——它们不会创建任何先行关系（happens-before 边），也没有任何顺序保证。实际上，relaxed 原子的读&#x2F;写与普通的读&#x2F;写之间没有区别，唯一的差别是 relaxed 原子上的数据竞争不被视为竞态条件，且不会导致未定义行为（即不会“引火”）。&lt;&#x2F;p&gt;
&lt;p&gt;修订后的 Java 内存模型的复杂性很大程度上来源于如何定义带有数据竞争程序的行为。如果 C++ 采用 DRF-SC（数据竞争自由时顺序一致性）或者 Catch Fire（捕捉竞态）模型——实质上是不允许存在数据竞争的程序——那么我们本可以抛弃之前提到的那些奇怪的例子，使 C++ 语言规范比 Java 更加简单。不幸的是，包含 relaxed 原子的做法最终还是保留了那些复杂问题，导致 C++11 规范并不比 Java 更简单。&lt;&#x2F;p&gt;
&lt;p&gt;像Java的内存模型一样，C ++ 11内存模型也最终出现不正确。从之前考虑以下情况：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Litmus Test: Non-Racy Out Of Thin Air Values&lt;&#x2F;em&gt;&lt;br&gt;
这个程序能否观察到 r1 = 42，r2 = 42？&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;
&#x2F;&#x2F; 线程 1                 &#x2F;&#x2F; 线程 2
r1 = x                    r2 = y
if (r1 == 42)             if (r2 == 42)
    y = r1                    x = r2
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;（显而易见不可能！）&lt;&#x2F;p&gt;
&lt;p&gt;C++11（普通变量）：&lt;strong&gt;不可能。&lt;&#x2F;strong&gt;&lt;br&gt;
C++11（relaxed 原子操作）：&lt;strong&gt;可能！&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;在他们的论文&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;fzn.fr&#x2F;readings&#x2F;c11comp.pdf&quot;&gt;《Common Compiler Optimisations are Invalid in the C11 Memory Model and what we can do about it》&lt;&#x2F;a&gt;（2015）中，Viktor Vafeiadis 等人展示了当 x 和 y 是普通变量时，C++11 规范保证该程序最终必须将 x 和 y 设为零。但如果 x 和 y 是 relaxed 原子变量，那么严格来说，C++11 规范并没有排除 r1 和 r2 都可能最终为 42 的情况。（令人惊讶！）&lt;&#x2F;p&gt;
&lt;p&gt;详情请参见论文，不过从高层次来看，C++11 规范制定了一些正式规则，试图禁止“无中生有”的数值，同时用一些模糊的措辞来阻止其他类型的问题值。那部分正式规则反而成了问题，因此 C++14 取消了这些规则，只保留了那些模糊的措辞。移除这些规则的理由是，C++11 的规定既“不充分”，使得几乎无法对使用 memory_order_relaxed 的程序进行合理推理；又“严重有害”，因为它实际上禁止了像 ARM 和 POWER 等架构上对 memory_order_relaxed 的合理实现。&lt;&#x2F;p&gt;
&lt;p&gt;总结一下，Java 试图形式上排除所有非因果执行，但失败了。随后，借助 Java 的经验教训，C++11 试图形式上排除部分非因果执行，也失败了。接着 C++14 则根本不做任何形式上的规定。这一趋势并不理想。&lt;&#x2F;p&gt;
&lt;p&gt;事实上，Mark Batty 等人在 2015 年发表的一篇题为&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;~jp622&#x2F;the_problem_of_programming_language_concurrency_semantics.pdf&quot;&gt;《The Problem of Programming Language Concurrency Semantics》&lt;&#x2F;a&gt;的论文给出了这样一个令人警醒的评价：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“令人不安的是，距离第一个支持 relaxed 内存模型的硬件（IBM 370&#x2F;158MP）推出已超过 40 年，领域内仍未有人提出一个可信的并发语义方案，适用于任何包含高性能共享内存并发原语的通用高级语言。”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;即使只是定义弱有序硬件的语义（忽略软件和编译器优化的复杂性）也进展不顺利。2018 年，Sizhuo Zhang 等人发表的一篇题为&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;1805.07886&quot;&gt;《Constructing a Weak Memory Model》&lt;&#x2F;a&gt;的论文回顾了近期的一些事件：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sarkar 等人在 2011 年为 POWER 架构发布了一个操作模型，Mador-Haim 等人在 2012 年发布了一个公理模型，证明其与操作模型一致。然而，2014 年，Alglave 等人展示了原操作模型及对应的公理模型无法解释在 POWER 机器上新观察到的行为。又比如，2016 年 Flur 等人为 ARM 提出了一个操作模型，但没有对应的公理模型。一年后，ARM 发布了其指令集架构手册的修订版，明确禁止了 Flur 模型允许的行为，并因此提出了另一种 ARM 内存模型。显然，经验性地形式化弱内存模型极易犯错且充满挑战。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;过去十年致力于定义和形式化这些问题的研究人员都非常聪明、有才华且坚持不懈，我并不想通过指出结果中的不足来贬低他们的努力与成就。我得出的结论是，即使在没有数据竞争的情况下，精确定义多线程程序的行为问题非常微妙且困难。如今，即使是最优秀的研究人员也难以完全掌握这件事。即使不是这样，一个编程语言的定义最好也能被普通开发者理解，而不需要花费十年时间去研究并发程序的语义。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;c-rust-and-swift-memory-models&quot;&gt;C, Rust and Swift Memory Models&lt;a class=&quot;zola-anchor&quot; href=&quot;#c-rust-and-swift-memory-models&quot; aria-label=&quot;Anchor link for: c-rust-and-swift-memory-models&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;C11 也采纳了 C++11 的内存模型，使其成为 C&#x2F;C++11 内存模型。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;sync&#x2F;atomic&#x2F;&quot;&gt;Rust 1.0.0&lt;&#x2F;a&gt; 于 2015 年和 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;apple&#x2F;swift-evolution&#x2F;blob&#x2F;master&#x2F;proposals&#x2F;0282-atomics.md&quot;&gt;Swift 5.3&lt;&#x2F;a&gt; 于 2020 年都完整采用了 C&#x2F;C++ 内存模型，包括 DRF-SC（数据竞争自由时顺序一致性）或 Catch Fire 机制，以及所有的原子类型和原子围栏。&lt;&#x2F;p&gt;
&lt;p&gt;这两种语言都采纳 C&#x2F;C++ 模型并不令人惊讶，因为它们都是基于 C&#x2F;C++ 编译器工具链（LLVM）构建的，并且强调与 C&#x2F;C++ 代码的紧密集成。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hardware-digression-efficient-sequentially-consistent-atomics-ying-jian-cha-qu-gao-xiao-de-shun-xu-yi-zhi-yuan-zi-cao-zuo&quot;&gt;Hardware Digression: Efficient Sequentially Consistent Atomics(硬件插曲：高效的顺序一致原子操作)&lt;a class=&quot;zola-anchor&quot; href=&quot;#hardware-digression-efficient-sequentially-consistent-atomics-ying-jian-cha-qu-gao-xiao-de-shun-xu-yi-zhi-yuan-zi-cao-zuo&quot; aria-label=&quot;Anchor link for: hardware-digression-efficient-sequentially-consistent-atomics-ying-jian-cha-qu-gao-xiao-de-shun-xu-yi-zhi-yuan-zi-cao-zuo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;早期的多处理器架构具有各种同步机制和内存模型，其可用性各不相同。在这种多样性中，不同同步抽象的效率取决于它们与架构提供的支持匹配得有多好。为了构建顺序一致原子变量的抽象，有时唯一的选择是使用比严格必要更复杂且更昂贵的屏障，尤其是在 ARM 和 POWER 平台上。&lt;&#x2F;p&gt;
&lt;p&gt;由于 C、C++ 和 Java 都提供了同样的顺序一致同步原子操作抽象，硬件设计者有责任让这种抽象更加高效。ARMv8 架构（包括 32 位和 64 位）引入了 ldar 和 stlr 加载和存储指令，提供了直接的实现支持。在 2017 年的一次演讲中，Herb Sutter 声称 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;youtu.be&#x2F;KeLBd2EJLOU?t=3432&quot;&gt;IBM 曾批准并表示&lt;&#x2F;a&gt;未来 POWER 实现将对顺序一致原子操作提供更高效的支持，从而减少程序员“使用 relaxed 原子操作的理由。”我无法确定这是否实现了，尽管到了 2021 年，POWER 已经变得远不如 ARMv8 重要。&lt;&#x2F;p&gt;
&lt;p&gt;这一趋同的效果是，现在顺序一致原子操作已被很好地理解，并且能够高效地在所有主流硬件平台上实现，使其成为编程语言内存模型的理想目标。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;javascript-memory-model-2017&quot;&gt;JavaScript Memory Model (2017)&lt;a class=&quot;zola-anchor&quot; href=&quot;#javascript-memory-model-2017&quot; aria-label=&quot;Anchor link for: javascript-memory-model-2017&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;你可能会认为，JavaScript 作为一个众所周知的单线程语言，不需要担心当代码在多个处理器上并行运行时的内存模型问题。我之前确实这么想。但你和我都会错。&lt;&#x2F;p&gt;
&lt;p&gt;JavaScript 有 web workers，它们允许在另一个线程中运行代码。最初的设计中，workers 仅通过显式消息复制与主 JavaScript 线程通信。由于没有共享的可写内存，也就不需要考虑数据竞争等问题。然而，ECMAScript 2017（ES2017）增加了 SharedArrayBuffer 对象，使得主线程和 workers 可以共享一块可写内存。为什么要这么做？在&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tc39&#x2F;ecmascript_sharedmem&#x2F;blob&#x2F;master&#x2F;historical&#x2F;Spec_JavaScriptSharedMemoryAtomicsandLocks.pdf&quot;&gt;一份提案的早期草案&lt;&#x2F;a&gt;中，列出的第一个原因就是为了将多线程 C++ 代码编译为 JavaScript。&lt;&#x2F;p&gt;
&lt;p&gt;当然，拥有共享的可写内存还需要定义用于同步的原子操作和内存模型。JavaScript 在三方面与 C++ 不同：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;首先，它将原子操作限制为仅支持顺序一致的原子操作。其他原子操作可以编译为顺序一致的原子操作，可能会有效率上的损失，但不会有正确性上的损失，只有一种类型简化了系统的其他部分。&lt;&#x2F;li&gt;
&lt;li&gt;其次，JavaScript 不采用“DRF-SC”或“Catch Fire”规则。相反，像 Java 一样，它仔细定义了竞态访问的可能结果。其理由与 Java 类似，特别是安全性方面。允许竞态读取返回任意值（完全允许，甚至可以说是鼓励）实现返回无关数据，这可能&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tc39&#x2F;ecmascript_sharedmem&#x2F;blob&#x2F;master&#x2F;DISCUSSION.md#races-leaking-private-data-at-run-time&quot;&gt;导致运行时泄露私有数据&lt;&#x2F;a&gt;。&lt;&#x2F;li&gt;
&lt;li&gt;第三，部分原因是 JavaScript 为竞态程序提供语义，它定义了当原子和非原子操作在同一内存位置使用时的行为，以及当同一内存位置通过不同大小访问时的行为。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;精确定义竞态程序的行为会带来松散内存语义的常见复杂性，以及如何禁止“空中楼阁”式读取等问题。除了这些挑战，这些挑战在其他地方也差不多，ES2017 定义中还有两个有趣的漏洞，源自与新 ARMv8 原子指令语义的不匹配。这些例子改编自 Conrad Watt 等人 2020 年的论文&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;~jp622&#x2F;repairing_javascript.pdf&quot;&gt;《修复和机制化 JavaScript 松散内存模型》&lt;&#x2F;a&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;正如我们在上一节中指出的，ARMv8 增加了 ldar 和 stlr 指令，提供顺序一致的原子加载和存储。这些指令是针对 C++ 设计的，而 C++ 并未定义任何带数据竞争程序的行为。因此，不出意外的是，这些指令在竞态程序中的行为与 ES2017 作者的预期不符，特别是它未能满足 ES2017 对竞态程序行为的要求。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Litmus Test：ARMv8 上的 ES2017 竞态读取&lt;&#x2F;em&gt;&lt;br&gt;
这个程序（使用原子操作）能看到 r1 = 0，r2 = 1 吗？&lt;&#x2F;p&gt;
&lt;pre&gt;
&#x2F;&#x2F; 线程 1               &#x2F;&#x2F; 线程 2
x = 1                  y = 1
r1 = y                 x = 2（非原子操作）
                       r2 = x
&lt;&#x2F;pre&gt;
&lt;p&gt;C++：可以（数据竞争，什么都可能发生）。&lt;br&gt;
Java：程序无法编写。&lt;br&gt;
ARMv8 使用 ldar&#x2F;stlr：可以。&lt;br&gt;
ES2017：&lt;em&gt;不可以！&lt;&#x2F;em&gt;（与 ARMv8 矛盾）&lt;&#x2F;p&gt;
&lt;p&gt;在这个程序中，除了 x = 2 之外，所有读写操作都是顺序一致的原子操作：线程 1 使用原子存储写入 x = 1，线程 2 使用非原子存储写入 x = 2。在 C++ 中，这是一个数据竞争，因此结果是不确定的。在 Java 中，这个程序无法编写：变量必须声明为 volatile 或者否则不能原子访问，而“只能有时访问”是不允许的。在 ES2017 中，内存模型不允许 r1 = 0 和 r2 = 1。如果 r1 = 1 且读取到 0，则线程 1 必须在线程 2 开始之前完成，这时非原子存储 x = 2 似乎发生在后面，覆盖了 x = 1，导致原子操作 r2 = x 读到 2。这个解释看起来完全合理，但这不是 ARMv8 处理器的工作方式。&lt;&#x2F;p&gt;
&lt;p&gt;事实证明，对于等效的 ARMv8 指令序列，非原子写入 x 可以被重新排序到原子写入 y 之前，因此这个程序实际上会产生 r1 = 0，r2 = 1。这个在 C++ 中不是问题，因为数据竞争意味着程序什么行为都可能出现，但在 ES2017 中这是个问题，因为它限制竞态行为的结果，不允许出现 r1 = 0，r2 = 1。&lt;&#x2F;p&gt;
&lt;p&gt;由于使用 ARMv8 指令实现顺序一致的原子操作是 ES2017 的一个明确目标，Watt 等人报告说他们建议的修正方案（计划纳入标准的下一次修订中）会适度放宽竞态行为的约束，从而允许上述结果发生。（我不清楚当时“下一次修订”指的是 ES2020 还是 ES2021。）&lt;&#x2F;p&gt;
&lt;p&gt;Watt 等人提出的修改还包括修复第二个漏洞，该漏洞最初由 Watt、Andreas Rossberg 和 Jean Pichon-Pharabod 发现，即一个无数据竞争的程序未被 ES2017 规范赋予顺序一致的语义。该程序如下：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Litmus Test：ES2017 无数据竞争程序&lt;&#x2F;em&gt;&lt;br&gt;
这个程序（使用原子操作）能看到 r1 = 1，r2 = 2 吗？&lt;&#x2F;p&gt;
&lt;pre&gt;
&#x2F;&#x2F; 线程 1                   &#x2F;&#x2F; 线程 2
x = 1                      x = 2
                           r1 = x
                           if (r1 == 1) {
                               r2 = x &#x2F;&#x2F; 非原子操作
                           }
&lt;&#x2F;pre&gt;
&lt;p&gt;在顺序一致的硬件上：不能。&lt;br&gt;
C++：我不是 C++ 专家，无法确定。&lt;br&gt;
Java：程序无法编写。&lt;br&gt;
ES2017：&lt;em&gt;可以！&lt;&#x2F;em&gt;（违反 DRF-SC 规则）。&lt;&#x2F;p&gt;
&lt;p&gt;在这个程序中，除了标记的 r2 = x 之外，所有读写操作都是顺序一致的原子操作。该程序无数据竞争：非原子读取（r2 = x）只在 r1 = 1 时执行，这证明线程 1 中的 x = 1 发生在线程 2 的 r1 = x 之前，因此也发生在 r2 = x 之前。DRF-SC（无数据竞争的顺序一致性）要求程序必须以顺序一致的方式执行，因此 r1 = 1，r2 = 2 是不可能的，但 ES2017 规范却允许了这种情况。&lt;&#x2F;p&gt;
&lt;p&gt;因此，ES2017 对程序行为的规范同时过于苛刻（不允许竞态程序的真实 ARMv8 行为）又过于宽松（允许无数据竞争程序出现非顺序一致的行为）。如前所述，这些错误已被修正。即便如此，这再次提醒我们，如何准确地用 happens-before 来定义无数据竞争和竞态程序的语义是多么微妙，以及如何让语言内存模型与底层硬件内存模型匹配同样复杂。&lt;&#x2F;p&gt;
&lt;p&gt;值得鼓舞的是，至少目前，JavaScript 避免添加除顺序一致原子操作外的其他原子操作，并抵制了“DRF-SC 或触发异常（Catch Fire）”的问题。这样产生的内存模型既适合作为 C&#x2F;C++ 的编译目标，又更接近 Java 的内存模型。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;a class=&quot;zola-anchor&quot; href=&quot;#conclusions&quot; aria-label=&quot;Anchor link for: conclusions&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;看待 C、C++、Java、JavaScript、Rust 和 Swift 时，我们可以做出以下观察：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;它们都提供顺序一致的同步原子操作，用于协调并行程序中的非原子部分。&lt;&#x2F;li&gt;
&lt;li&gt;它们都旨在保证通过适当同步实现的数据竞争自由程序的行为，表现得如同以顺序一致的方式执行。&lt;&#x2F;li&gt;
&lt;li&gt;Java 一直到 Java 9 引入 VarHandle 之前，都抗拒添加弱（acquire&#x2F;release）同步原子操作。JavaScript 则避免添加它们，直到撰写本文时。&lt;&#x2F;li&gt;
&lt;li&gt;它们都为程序提供了一种执行“有意”的数据竞争的方式，而不会使程序的其余部分无效。在 C、C++、Rust 和 Swift 中，这种机制是松散的、非同步的原子操作，是一种特殊形式的内存访问。在 Java 中，这种机制要么是普通内存访问，要么是 Java 9 中 VarHandle 的“plain”访问模式。在 JavaScript 中，这种机制是普通内存访问。&lt;&#x2F;li&gt;
&lt;li&gt;没有任何语言找到正式禁止诸如“空中阁楼值（out-of-thin-air values）”这类悖论的方法，但所有语言非正式地禁止它们。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;与此同时，处理器制造商似乎已经接受了顺序一致同步原子操作这一抽象的重要性，且开始高效实现它：ARMv8 和 RISC-V 都提供了直接支持。&lt;&#x2F;p&gt;
&lt;p&gt;最后，大量的验证和形式化分析工作已经投入到理解这些系统并精确定义其行为中。尤其令人鼓舞的是，Watt 等人在 2020 年成功给出了 JavaScript 的一个重要子集的形式模型，并使用定理证明器证明了将其编译到 ARM、POWER、RISC-V 和 x86-TSO 的正确性。&lt;&#x2F;p&gt;
&lt;p&gt;在第一个 Java 内存模型发布二十五年后，经过大量人年的研究努力，我们可能正开始能够形式化完整的内存模型。也许有一天，我们将完全理解它们。&lt;&#x2F;p&gt;
&lt;p&gt;本系列的下一篇文章是《Updating the Go Memory Model》。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;acknowledgements-zhi-xie&quot;&gt;Acknowledgements(致谢)&lt;a class=&quot;zola-anchor&quot; href=&quot;#acknowledgements-zhi-xie&quot; aria-label=&quot;Anchor link for: acknowledgements-zhi-xie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;这一系列文章得益于我在谷歌有幸合作的一长串工程师们的讨论和反馈。在此感谢他们。所有错误或不受欢迎的观点由我本人全权负责。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;plmm&quot;&gt;https:&#x2F;&#x2F;research.swtch.com&#x2F;plmm&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | 原子操作和同步原语</title>
          <pubDate>Fri, 18 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-18-atomic-operations-and-synchronization-primitives/</link>
          <guid>https://inasa.dev/posts/25-04-18-atomic-operations-and-synchronization-primitives/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-18-atomic-operations-and-synchronization-primitives/">&lt;p&gt;在高并发系统中，性能不仅关乎你做了什么，更关乎你避免了什么。锁竞争、缓存行抖动和内存屏障在你达到扩展瓶颈之前，就悄悄地影响了吞吐量。原子操作是 &lt;code&gt;Go&lt;&#x2F;code&gt; 语言提供的最轻量级工具之一，能够有效规避这些问题。&lt;&#x2F;p&gt;
&lt;p&gt;虽然 &lt;code&gt;Go&lt;&#x2F;code&gt; 提供了完整的同步原语套件，但有些问题使用锁会显得过于繁重。原子操作则在低层协调中（如计数器、标志和简单状态机）提供了更清晰且更高效的解决方案，尤其是在高压环境下表现突出。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;li-jie-yuan-zi-cao-zuo&quot;&gt;理解原子操作&lt;a class=&quot;zola-anchor&quot; href=&quot;#li-jie-yuan-zi-cao-zuo&quot; aria-label=&quot;Anchor link for: li-jie-yuan-zi-cao-zuo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;原子操作允许对共享数据进行安全的并发访问，而无需像互斥锁（&lt;code&gt;mutex&lt;&#x2F;code&gt;）那样的显式锁机制。&lt;code&gt;sync&#x2F;atomic&lt;&#x2F;code&gt; 包提供了低级别的原子内存原语，非常适合用于计数器、标志或简单的状态转换。&lt;&#x2F;p&gt;
&lt;p&gt;原子操作的关键优势是在高竞争情况下的性能表现。加锁会引入协调开销——当许多 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 争夺同一个互斥锁时，性能可能因上下文切换和锁队列管理而下降。原子操作通过在硬件层面，利用 &lt;code&gt;CPU&lt;&#x2F;code&gt; 指令（如 &lt;code&gt;CAS&lt;&#x2F;code&gt;，比较并交换）直接操作，避免了这些开销。这使得原子操作在以下场景中特别有用：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;高吞吐量的计数器和标志&lt;&#x2F;li&gt;
&lt;li&gt;无锁队列和无锁空闲列表&lt;&#x2F;li&gt;
&lt;li&gt;不适合使用锁的低延迟路径&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;nei-cun-mo-xing-ji-yu-c-de-bi-jiao&quot;&gt;内存模型及与 &lt;code&gt;C++&lt;&#x2F;code&gt; 的比较&lt;a class=&quot;zola-anchor&quot; href=&quot;#nei-cun-mo-xing-ji-yu-c-de-bi-jiao&quot; aria-label=&quot;Anchor link for: nei-cun-mo-xing-ji-yu-c-de-bi-jiao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;理解内存模型在推理并发行为时至关重要。在 &lt;code&gt;C++&lt;&#x2F;code&gt; 中，开发者可以通过内存序（&lt;code&gt;memory order&lt;&#x2F;code&gt;）对原子操作进行细粒度控制，从而在性能和一致性之间做权衡。默认情况下，&lt;code&gt;Go&lt;&#x2F;code&gt; 语言的原子操作强制执行顺序一致性（&lt;code&gt;sequential consistency&lt;&#x2F;code&gt;），这意味着它们的行为类似于 &lt;code&gt;C++&lt;&#x2F;code&gt; 中的 &lt;code&gt;std::memory_order_seq_cst&lt;&#x2F;code&gt;。这是最强且最安全的内存序保证：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;所有线程都以相同的顺序观察原子操作。&lt;&#x2F;li&gt;
&lt;li&gt;在每个操作的前后都会应用完整的内存屏障。&lt;&#x2F;li&gt;
&lt;li&gt;原子操作之间的读写不会被重排。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;C++ Memory Order&lt;&#x2F;th&gt;&lt;th&gt;Go Equivalent&lt;&#x2F;th&gt;&lt;th&gt;Notes&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;memory_order_seq_cst&lt;&#x2F;td&gt;&lt;td&gt;All atomic.* ops&lt;&#x2F;td&gt;&lt;td&gt;Full sequential consistency&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;memory_order_acquire&lt;&#x2F;td&gt;&lt;td&gt;Not exposed&lt;&#x2F;td&gt;&lt;td&gt;Not available in Go&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;memory_order_release&lt;&#x2F;td&gt;&lt;td&gt;Not exposed&lt;&#x2F;td&gt;&lt;td&gt;Not available in Go&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;memory_order_relaxed&lt;&#x2F;td&gt;&lt;td&gt;Not exposed&lt;&#x2F;td&gt;&lt;td&gt;Not available in Go&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;&lt;code&gt;Go&lt;&#x2F;code&gt; 语言不暴露诸如 &lt;code&gt;relaxed&lt;&#x2F;code&gt;、&lt;code&gt;acquire&lt;&#x2F;code&gt; 或 &lt;code&gt;release&lt;&#x2F;code&gt; 这类较弱的内存模型。这是刻意简化设计，以提升安全性并降低细微数据竞争的风险。&lt;code&gt;Go&lt;&#x2F;code&gt; 中所有的原子操作隐式实现了 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 间的同步，确保了正确的行为，无需手动管理内存屏障。&lt;&#x2F;p&gt;
&lt;p&gt;这意味着你不必关注指令重排或内存可见性等底层细节，但也意味着你无法像 &lt;code&gt;C++&lt;&#x2F;code&gt; 或 &lt;code&gt;Rust&lt;&#x2F;code&gt; 开发者那样，通过使用 &lt;code&gt;relaxed&lt;&#x2F;code&gt; 原子操作对性能进行细粒度调优。&lt;&#x2F;p&gt;
&lt;p&gt;在 &lt;code&gt;Go&lt;&#x2F;code&gt; 内部（例如在运行时或通过 &lt;code&gt;go:linkname&lt;&#x2F;code&gt;），存在对放宽内存序的低级访问，但这不安全且不支持应用层代码使用。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;chang-yong-de-yuan-zi-cao-zuo&quot;&gt;常用的原子操作&lt;a class=&quot;zola-anchor&quot; href=&quot;#chang-yong-de-yuan-zi-cao-zuo&quot; aria-label=&quot;Anchor link for: chang-yong-de-yuan-zi-cao-zuo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;atomic.AddInt64&lt;&#x2F;code&gt;、&lt;code&gt;atomic.AddUint32&lt;&#x2F;code&gt; 等：原子地执行加法操作。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;atomic.LoadInt64&lt;&#x2F;code&gt;、&lt;code&gt;atomic.LoadPointer&lt;&#x2F;code&gt;：原子地读取值。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;atomic.StoreInt64&lt;&#x2F;code&gt;、&lt;code&gt;atomic.StorePointer&lt;&#x2F;code&gt;：原子地写入值。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;atomic.CompareAndSwapInt64&lt;&#x2F;code&gt;：原子地有条件更新一个值。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;yuan-zi-cao-zuo-zai-shi-ji-zhong-de-shi-yong-shi-ji&quot;&gt;原子操作在实际中的使用时机&lt;a class=&quot;zola-anchor&quot; href=&quot;#yuan-zi-cao-zuo-zai-shi-ji-zhong-de-shi-yong-shi-ji&quot; aria-label=&quot;Anchor link for: yuan-zi-cao-zuo-zai-shi-ji-zhong-de-shi-yong-shi-ji&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;gao-tun-tu-liang-de-zhi-biao-he-ji-shu-qi&quot;&gt;高吞吐量的指标和计数器&lt;a class=&quot;zola-anchor&quot; href=&quot;#gao-tun-tu-liang-de-zhi-biao-he-ji-shu-qi&quot; aria-label=&quot;Anchor link for: gao-tun-tu-liang-de-zhi-biao-he-ji-shu-qi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;用于跟踪请求数量、丢包数或其他轻量级统计数据：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;requests&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;atomic&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Int64&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;handleRequest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;requests&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Add&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这段代码允许多个 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 在不使用锁的情况下安全地递增共享计数器。&lt;code&gt;atomic.AddInt64&lt;&#x2F;code&gt; 确保每次加法操作都是原子性的，防止了竞态条件，并在高负载情况下保持高性能。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;kuai-su-de-wu-suo-biao-zhi&quot;&gt;快速的无锁标志&lt;a class=&quot;zola-anchor&quot; href=&quot;#kuai-su-de-wu-suo-biao-zhi&quot; aria-label=&quot;Anchor link for: kuai-su-de-wu-suo-biao-zhi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;多个线程间共享的简单布尔状态：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;shutdown&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;atomic&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Int32&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;mainLoop&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;shutdown&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Load&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;break&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 执行工作
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;stop&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;shutdown&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Store&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这种模式允许一个 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 向另一个发送停止信号。&lt;code&gt;atomic.LoadInt32&lt;&#x2F;code&gt; 以同步保证读取标志，&lt;code&gt;atomic.StoreInt32&lt;&#x2F;code&gt; 以对所有 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 可见的方式设置标志。这有助于实现安全的关闭信号。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;zhi-zhi-xing-yi-ci-de-chu-shi-hua&quot;&gt;只执行一次的初始化&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhi-zhi-xing-yi-ci-de-chu-shi-hua&quot; aria-label=&quot;Anchor link for: zhi-zhi-xing-yi-ci-de-chu-shi-hua&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;当你需要更灵活的控制时，可以替代 &lt;code&gt;sync.Once&lt;&#x2F;code&gt;：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;initialized&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;atomic&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Int32&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;maybeInit&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;initialized&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;CompareAndSwap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 初始化资源
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这段代码使用 &lt;code&gt;CompareAndSwapInt32&lt;&#x2F;code&gt; 确保只有第一个看到 &lt;code&gt;initialized == 0&lt;&#x2F;code&gt; 的 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 会执行初始化逻辑，其他 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 都会跳过。这种方式高效且避免了 &lt;code&gt;sync.Once&lt;&#x2F;code&gt; 的锁开销，特别适合你需要条件性初始化或重试机制的场景。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;wu-suo-dui-lie-huo-kong-xian-lian-biao-jie-gou&quot;&gt;无锁队列或空闲链表结构&lt;a class=&quot;zola-anchor&quot; href=&quot;#wu-suo-dui-lie-huo-kong-xian-lian-biao-jie-gou&quot; aria-label=&quot;Anchor link for: wu-suo-dui-lie-huo-kong-xian-lian-biao-jie-gou&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;构建高性能的数据结构：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;node&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;next&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;node&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;val&lt;&#x2F;span&gt;  &lt;span class=&quot;z-storage z-type z-go&quot;&gt;any&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;head&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;atomic&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;node&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;push&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;n&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;node&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;old&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Load&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;next&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;old&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;head&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;CompareAndSwap&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;old&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这段代码实现了一个无锁栈（后进先出队列）。它通过原子地替换头指针来反复尝试将节点插入到链表头部，只有当头指针没有变化时才替换——这是经典的 &lt;code&gt;CAS&lt;&#x2F;code&gt;（比较并交换）循环。该方法常用于对象池和工作窃取队列中。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;jian-shao-suo-jing-zheng&quot;&gt;减少锁竞争&lt;a class=&quot;zola-anchor&quot; href=&quot;#jian-shao-suo-jing-zheng&quot; aria-label=&quot;Anchor link for: jian-shao-suo-jing-zheng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;这种方法在实际系统中很常见，用于减少不必要的锁竞争，比如功能开关、一次性初始化路径或条件缓存机制。原子操作（&lt;code&gt;atomic&lt;&#x2F;code&gt;）作为获取更昂贵锁之前的快速路径过滤器。&lt;&#x2F;p&gt;
&lt;p&gt;将原子操作与互斥锁（&lt;code&gt;mutex&lt;&#x2F;code&gt;）结合起来控制昂贵操作：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;atomic&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;LoadInt32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;someFlag&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;mu&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Lock&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;defer&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;mu&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Unclock&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 进行一些耗时操作
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;当 &lt;code&gt;someFlag&lt;&#x2F;code&gt; 由另一个 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 设置，而当前 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 仅将其作为只读信号判断是否继续时，这种模式很有效。它避免在高吞吐路径中不必要的锁获取，比如在功能被禁用或任务已完成时短路执行。&lt;&#x2F;p&gt;
&lt;p&gt;然而，如果同一个 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 也负责设置该标志，那么单纯的先加载后加锁是不安全的。另一个 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 可能在检查和加锁之间插入操作，导致不一致的行为。&lt;&#x2F;p&gt;
&lt;p&gt;为了保证操作的安全和原子性，应使用 &lt;code&gt;CompareAndSwap&lt;&#x2F;code&gt;：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;atomic&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;CompareAndSwapInt32&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;someFlag&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 工作已经在进行中或已完成
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;mu&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Lock&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;defer&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;mu&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Unlock&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 执行一次性昂贵初始化
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;该版本保证只有一个 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 继续执行，其他的提前退出。它确保对 &lt;code&gt;someFlag&lt;&#x2F;code&gt; 的检查和更新是原子的。&lt;&#x2F;p&gt;
&lt;p&gt;这里，原子读取充当快速守门员。如果标志未设置，则无需获取互斥锁。这避免了高频代码路径中不必要的锁定，提高了系统在负载下的响应能力。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tong-bu-yuan-yu&quot;&gt;同步原语&lt;a class=&quot;zola-anchor&quot; href=&quot;#tong-bu-yuan-yu&quot; aria-label=&quot;Anchor link for: tong-bu-yuan-yu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;本节内容刻意保持简洁。&lt;code&gt;Go&lt;&#x2F;code&gt; 语言的同步原语——例如 &lt;code&gt;sync.Mutex&lt;&#x2F;code&gt;、&lt;code&gt;sync.RWMutex&lt;&#x2F;code&gt; 和 &lt;code&gt;sync.Cond&lt;&#x2F;code&gt; ——已经有非常完善的文档和广泛的理解。它们是管理共享内存和协调 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 的重要工具，但它们并非本篇文章的重点。&lt;&#x2F;p&gt;
&lt;p&gt;在本文的语境中，我们仅将它们作为与原子操作进行性能对比的基准。适当地使用这些原语可以带来清晰性和正确性，但它们在高竞争场景下通常代价较高，而原子操作则可提供更轻量的替代方案。&lt;&#x2F;p&gt;
&lt;p&gt;我们将以这些原语作为对比点，来突出何时以及为何原子操作可能带来性能优势。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ji-zhun-ce-shi-ying-xiang&quot;&gt;基准测试影响&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-zhun-ce-shi-ying-xiang&quot; aria-label=&quot;Anchor link for: ji-zhun-ce-shi-ying-xiang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;为了理解原子操作与互斥锁（&lt;code&gt;mutex&lt;&#x2F;code&gt;）之间的性能差异，我们可以通过一个简单的基准测试来比较多个 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 同时递增共享计数器所需的时间。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;BenchmarkAtomicIncrement&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;b&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;B&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;counter&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;RunParallel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;pb&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;PB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;pb&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Next&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-variable z-other z-go&quot;&gt;atomic&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;AddInt64&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;counter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;BenchmarkMutexIncrement&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;b&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;B&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;counter&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;mu&lt;&#x2F;span&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;sync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Mutex&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;RunParallel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;pb&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;testing&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;PB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;pb&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Next&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-variable z-other z-go&quot;&gt;mu&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Lock&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-variable z-other z-go&quot;&gt;counter&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;++&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-variable z-other z-go&quot;&gt;mu&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Unlock&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这段代码通过两种方式分别对共享变量执行递增操作，并使用 &lt;code&gt;b.RunParallel&lt;&#x2F;code&gt; 让不同的 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 并行执行，从而测量原子操作与互斥锁在并发情况下的性能表现差异。&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Benchmark&lt;&#x2F;th&gt;&lt;th&gt;　Iterations&lt;&#x2F;th&gt;&lt;th&gt;　Time per op (ns)&lt;&#x2F;th&gt;&lt;th&gt;　Bytes per op&lt;&#x2F;th&gt;&lt;th&gt;　Allocs per op&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;BenchmarkAtomicIncrement-14&lt;&#x2F;td&gt;&lt;td&gt;39,910,514&lt;&#x2F;td&gt;&lt;td&gt;80.40&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;BenchmarkMutexIncrement-14&lt;&#x2F;td&gt;&lt;td&gt;32,629,298&lt;&#x2F;td&gt;&lt;td&gt;110.7&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;原子操作在吞吐量和延迟方面均优于基于互斥锁的递增操作。随着锁争用加剧，这种差异会更加明显，因为避免获取锁有助于减少上下文切换和调度器开销。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;he-shi-shi-yong-yuan-zi-cao-zuo-vs-hu-chi-suo&quot;&gt;何时使用原子操作 vs. 互斥锁&lt;a class=&quot;zola-anchor&quot; href=&quot;#he-shi-shi-yong-yuan-zi-cao-zuo-vs-hu-chi-suo&quot; aria-label=&quot;Anchor link for: he-shi-shi-yong-yuan-zi-cao-zuo-vs-hu-chi-suo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;原子操作在简单且高频率的场景中表现出色——比如计数器、标志、协调信号等——在这些场景中锁的开销是不成比例的。它们能够避免锁队列和减少上下文切换。但它们也有局限性：无法将多个操作组合在一起，不能回滚，且在超出其适用范围后会增加复杂性。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;互斥锁仍然是管理复杂共享状态、保护多步骤临界区以及维护不变量的正确工具。当程序逻辑超过几行时，互斥锁更容易理解且通常更安全。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;选择使用原子操作还是锁，不是出于理念，而是根据具体范围。当任务简单时，原子操作能轻松应对；当任务变复杂时，锁才能保障安全。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;goperf.dev&#x2F;01-common-patterns&#x2F;atomic-ops&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | Memory Models, Part 1-Hardware Memory Models</title>
          <pubDate>Fri, 18 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-18-hardwarememory-models/</link>
          <guid>https://inasa.dev/posts/25-04-18-hardwarememory-models/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-18-hardwarememory-models/">&lt;h2 id=&quot;introduction-a-fairy-tale-ending-jie-shao-tong-hua-gu-shi-de-jie-ju&quot;&gt;Introduction: A Fairy Tale, Ending(介绍：童话故事的结局)&lt;a class=&quot;zola-anchor&quot; href=&quot;#introduction-a-fairy-tale-ending-jie-shao-tong-hua-gu-shi-de-jie-ju&quot; aria-label=&quot;Anchor link for: introduction-a-fairy-tale-ending-jie-shao-tong-hua-gu-shi-de-jie-ju&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;很久以前，当所有人都编写单线程程序时，使程序运行更快的最有效方法之一就是坐视不动。下一代硬件和下一代编译器的优化会让程序运行得一模一样，只是更快。在这个童话故事时期，有一个简单的测试来判断优化是否有效：如果程序员无法分辨未经优化和经过优化的有效程序的区别（除了加速的差异），那么优化就是有效的。也就是说，有效的优化不会改变有效程序的行为。&lt;&#x2F;p&gt;
&lt;p&gt;多年以前，有一天令人难过的事情发生了，硬件工程师使单个处理器变得越来越快的魔法咒语失效了。作为回应，他们找到了一个新的魔法咒语，让他们能够制造出拥有越来越多处理器的计算机，操作系统通过线程这一抽象向程序员暴露了这种硬件并行性。这种新的魔法咒语——以操作系统线程形式提供的多处理器——对硬件工程师来说效果更好，但却为语言设计者、编译器编写者和程序员带来了重大问题。&lt;&#x2F;p&gt;
&lt;p&gt;许多在单线程程序中是不可见（因此有效）的硬件和编译器优化，在多线程程序中会产生可见的变化。如果有效的优化不应改变有效程序的行为，那么这些优化或者现有程序必须被判定为无效。究竟是哪一种情况，我们又该如何做出判断呢？&lt;&#x2F;p&gt;
&lt;p&gt;这里有一个用类似C语言写的简单示例程序。在这个程序以及我们将考虑的所有程序中，所有变量初始值均为零。&lt;&#x2F;p&gt;
&lt;div style=&quot;display: flex; font-family: monospace; white-space: pre;&quot;&gt;
  &lt;div style=&quot;padding-right: 40px;&quot;&gt;
&#x2F;&#x2F; Thread 1
x = 1;
done = 1;
  &lt;&#x2F;div&gt;
  &lt;div&gt;
&#x2F;&#x2F; Thread 2
while(done == 0) { &#x2F;* loop *&#x2F; }
print(x);
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;如果线程1和线程2各自运行在独立的处理器上，并且都能运行至完成，这个程序能打印出0吗？&lt;&#x2F;p&gt;
&lt;p&gt;这要看情况。它依赖于硬件，也依赖于编译器。在x86多处理器上，逐行翻译成汇编语言并运行的程序总是会打印1。但在ARM或POWER多处理器上，逐行翻译成汇编语言并运行的程序可能打印0。此外，无论底层硬件如何，标准的编译器优化可能使该程序打印0或进入无限循环。&lt;&#x2F;p&gt;
&lt;p&gt;“这要看情况”并不是一个令人满意的结局。程序员需要一个明确的答案，来确定程序是否能在新硬件和新编译器下继续正常工作。硬件设计者和编译器开发者也需要一个明确的答案，来精确说明在执行某个程序时硬件和编译代码允许以何种方式表现。由于这里的主要问题是存储在内存中数据的更改的可见性和一致性，这种约定被称为内存一致性模型，或简称内存模型（memory model）。&lt;&#x2F;p&gt;
&lt;p&gt;最初，内存模型的目标是定义硬件向编写汇编代码的程序员所保证的内容。在那个背景下，编译器并不参与其中。二十五年前，人们开始尝试编写内存模型，定义诸如Java或C++这样的高级编程语言，向使用这些语言编写代码的程序员所保证的内容。将编译器纳入模型，使得定义一个合理的模型变得更加复杂。&lt;&#x2F;p&gt;
&lt;p&gt;这是关于硬件内存模型和编程语言内存模型的&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;mm&quot;&gt;两篇文章中的第一篇&lt;&#x2F;a&gt;。我的写作目的，是为讨论我们可能想在 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;gomm&quot;&gt;Go 语言内存模型&lt;&#x2F;a&gt;中做出的潜在变更打好基础。但为了理解 Go 语言的现状和未来走向，首先我们必须了解其他硬件内存模型和语言内存模型目前的发展状况，以及它们为达到如今状态所经历的风险路径。&lt;&#x2F;p&gt;
&lt;p&gt;再次说明，这篇文章是关于硬件的。假设我们正在为一台多处理器计算机编写汇编语言。程序员需要计算机硬件提供什么保证，才能编写出正确的程序？计算机科学家们对这个问题的研究已经超过四十年。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sequential-consistency-shun-xu-yi-zhi-xing&quot;&gt;Sequential Consistency(顺序一致性)&lt;a class=&quot;zola-anchor&quot; href=&quot;#sequential-consistency-shun-xu-yi-zhi-xing&quot; aria-label=&quot;Anchor link for: sequential-consistency-shun-xu-yi-zhi-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Leslie Lamport 在1979年的论文&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.microsoft.com&#x2F;en-us&#x2F;research&#x2F;publication&#x2F;make-multiprocessor-computer-correctly-executes-multiprocess-programs&#x2F;&quot;&gt;《如何制造一台能正确执行多进程程序的多处理器计算机》&lt;&#x2F;a&gt;中提出了顺序一致性的概念：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;设计和证明多处理器算法正确性的惯常方法假设满足以下条件：任何执行的结果都与所有处理器的操作按某种顺序依次执行的结果相同，且每个处理器的各个操作按其程序指定的顺序出现在该序列中。满足这一条件的多处理器称为顺序一致的。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;如今我们不仅谈论计算机硬件，还谈论保证顺序一致性的编程语言，其中程序的所有可能执行对应于线程操作某种交织后的顺序执行。顺序一致性通常被视为理想模型，是程序员最自然的工作模型。它允许你假设程序按代码中出现的顺序执行，而各线程的执行只是以某种顺序交织在一起，但不会被其他方式重排。&lt;&#x2F;p&gt;
&lt;p&gt;有人可能会合理地质疑顺序一致性是否应该是理想模型，但这超出了本文的讨论范围。我只想指出，考虑所有可能的线程交织，今天和1979年一样，仍然是“设计和证明多处理器算法正确性的惯常方法。”在过去的四十年中，尚无其他方法取而代之。&lt;&#x2F;p&gt;
&lt;p&gt;之前我问过这个程序是否能打印0：&lt;&#x2F;p&gt;
&lt;div style=&quot;display: flex; font-family: monospace; white-space: pre;&quot;&gt;
  &lt;div style=&quot;flex: 1; padding: 10px; padding-right: 20px;&quot;&gt;
&#x2F;&#x2F; 线程 1
x = 1;
done = 1;
  &lt;&#x2F;div&gt;
  &lt;div style=&quot;flex: 1; padding: 10px;&quot;&gt;
&#x2F;&#x2F; 线程 2
while(done == 0) { &#x2F;* 循环 *&#x2F; }
print(x);
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;为了让程序更容易分析，我们去掉循环和打印操作，询问读取共享变量时可能的结果：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;试金石测试：消息传递&lt;&#x2F;em&gt;&lt;br&gt;
该程序能否出现 r1 = 1，r2 = 0 这样的情况？&lt;&#x2F;p&gt;
&lt;div style=&quot;display: flex; font-family: monospace; white-space: pre;&quot;&gt;
  &lt;div style=&quot;flex: 1; padding: 10px; padding-right: 20px;&quot;&gt;
&#x2F;&#x2F; 线程 1
x = 1
y = 1
  &lt;&#x2F;div&gt;
  &lt;div style=&quot;flex: 1; padding: 10px;&quot;&gt;
&#x2F;&#x2F; 线程 2
r1 = y
r2 = x
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;我们假设每个示例都以所有共享变量初始化为零开始。由于我们试图确定硬件允许做什么，我们假设每个线程都在其独立的处理器上执行，且没有编译器对线程内部的操作进行重排序：代码清单中的指令即处理器执行的指令。rN 表示线程本地寄存器，而非共享变量，我们关心在程序执行结束时，某种线程本地寄存器的设置是否可能出现。&lt;&#x2F;p&gt;
&lt;p&gt;这类关于程序执行结果的问题称为“试金石测试”（litmus test）。因为它的答案是二元的——这个结果是否可能？——试金石测试为我们区分内存模型提供了明确的方法：如果某个模型允许某执行结果，而另一个模型不允许，则两者明显不同。不幸的是，正如我们稍后会看到的，某个模型对特定试金石测试的回答经常令人惊讶。&lt;&#x2F;p&gt;
&lt;p&gt;如果这个试金石测试的执行是顺序一致的，那么只有六种可能的交织方式：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;mem-litmus@2x.png&quot; alt=&quot;six possible interleavings&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;由于没有任何交织会导致 r1 = 1，r2 = 0 的情况，所以这个结果是不允许的。也就是说，在顺序一致的硬件上，试金石测试——“这个程序是否会出现 r1 = 1，r2 = 0？”的答案是否定的。&lt;&#x2F;p&gt;
&lt;p&gt;顺序一致性的一个良好心理模型是，想象所有处理器都直接连接到同一个共享内存，该内存一次只能服务于来自一个线程的读或写请求。这里没有任何缓存，因此每当处理器需要从内存读取或写入数据时，请求都会直接发送到共享内存。这个一次只允许一个访问者使用的共享内存，对所有内存访问的执行顺序施加了顺序约束：这就是顺序一致性。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;mem-sc@2x.png&quot; alt=&quot;sequential consistency&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;本文中三张内存模型硬件图改编自 Maranget 等人的&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;~pes20&#x2F;ppc-supplemental&#x2F;test7.pdf&quot;&gt;《ARM 和 POWER 弛豫内存模型教程导读》&lt;&#x2F;a&gt;。）&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“弛豫”在计算机科学，尤其是内存模型领域，指的是对严格顺序执行或一致性要求的放宽。也就是说，内存访问操作不必严格按程序中写的顺序执行，而是允许一定程度的重排序或延迟，从而提高硬件和软件的性能。比如“弛豫内存模型”（relaxed memory model）就是指允许内存操作顺序部分放宽的内存一致性模型。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;这个图示是一个顺序一致机器的模型，而不是构建这种机器的唯一方式。实际上，可以使用多个共享内存模块和缓存来构建一个顺序一致的机器，从而帮助预测内存访问的结果，但顺序一致意味着机器的行为必须与该模型无异。如果我们只是想理解什么是顺序一致的执行，那么可以忽略所有可能的实现细节，只专注于这个模型。&lt;&#x2F;p&gt;
&lt;p&gt;对于我们程序员来说，不幸的是，放弃严格的顺序一致性可以让硬件更快地执行程序，因此所有现代硬件在各种方式上都会偏离顺序一致的行为。准确定义具体硬件的偏离方式其实是很困难的。本文以两个例子来说明当今广泛使用的硬件中存在的两种内存模型：x86架构的，以及ARM和POWER处理器家族的。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;x86-total-store-order-x86-tso-x86-quan-bu-xie-ru-shun-xu&quot;&gt;x86 Total Store Order (x86-TSO)(x86 全部写入顺序)&lt;a class=&quot;zola-anchor&quot; href=&quot;#x86-total-store-order-x86-tso-x86-quan-bu-xie-ru-shun-xu&quot; aria-label=&quot;Anchor link for: x86-total-store-order-x86-tso-x86-quan-bu-xie-ru-shun-xu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;现代 x86 系统的内存模型对应于这个硬件图示：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;mem-tso@2x.png&quot; alt=&quot;The memory model for modern x86 systems&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;所有处理器仍然连接到单个共享内存，但每个处理器将写入该内存的操作排队到本地写入队列中。处理器在写入操作传递到共享内存的过程中，继续执行新的指令。在一个处理器上进行的内存读取会先查看本地写入队列，然后才访问主内存，但它无法看到其他处理器的写入队列。其效果是，处理器能比其他处理器更早看到自己发出的写入操作。但——这点非常重要——所有处理器都同意写入（存储）达到共享内存的（总）顺序，这就是该模型名称的由来：total store order，简称 TSO。当前，写入一旦达到共享内存，任何处理器对该内存位置的后续读取都会看到并使用该值（直到被后续写入覆盖，或者被来自其他处理器的缓存写入缓冲覆盖）。&lt;&#x2F;p&gt;
&lt;p&gt;写入队列是一个标准的先进先出（FIFO）队列：内存写入操作以处理器执行的相同顺序应用到共享内存中。由于写入顺序由写入队列保持，而且其他处理器也能立即看到写入共享内存的操作，我们之前考虑的消息传递灯塔测试仍然会得到相同的结果：r1 = 1，r2 = 0 依然不可能出现。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;试金石测试：消息传递&lt;&#x2F;em&gt;&lt;br&gt;
这个程序能看到 r1 = 1，r2 = 0 吗？&lt;&#x2F;p&gt;
&lt;div style=&quot;display: flex; justify-content: space-between; font-family: monospace; white-space: pre; width: 400px;&quot;&gt;
  &lt;div&gt;
&#x2F;&#x2F; Thread 1
x = 1
y = 1
  &lt;&#x2F;div&gt;
  &lt;div&gt;
&#x2F;&#x2F; Thread 2
r1 = y
r2 = x
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;在顺序一致的硬件上：不能。&lt;br&gt;
在 x86（或其他 TSO）上：也不能。&lt;&#x2F;p&gt;
&lt;p&gt;写入队列保证线程1先将x写入内存，再写入y，并且系统范围内对内存写入顺序的共识（即总写入顺序）保证线程2在得知y的新值之前先得知x的新值。因此，不可能出现r1 = y看到新的y值而r2 = x未看到新的x值的情况。这里写入顺序非常关键：线程1先写x再写y，所以线程2不可能先看到写入y的操作而没看到写入x的操作。&lt;&#x2F;p&gt;
&lt;p&gt;顺序一致性模型和TSO模型在这种情况下是相同的，但它们对其他试金石测试的结果存在分歧。例如，下面是区分这两种模型的常用示例：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;试金石测试：写入队列（也称为存储缓冲区）&lt;&#x2F;em&gt;&lt;br&gt;
这个程序能看到 r1 = 0，r2 = 0 吗？&lt;&#x2F;p&gt;
&lt;div style=&quot;display: flex; justify-content: space-between; font-family: monospace; white-space: pre; width: 400px;&quot;&gt;
  &lt;div&gt;
&#x2F;&#x2F; Thread 1
x = 1
r1 = y
  &lt;&#x2F;div&gt;
  &lt;div&gt;
&#x2F;&#x2F; Thread 2
y = 1
r2 = x
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;在顺序一致性硬件上：不能。&lt;br&gt;
在 x86（或其他 TSO）上：&lt;strong&gt;可以！&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;在任何顺序一致性执行中，要么先发生 x = 1，要么先发生 y = 1，然后另一线程的读取必须观察到这个写入，因此 r1 = 0，r2 = 0 是不可能的。但在 TSO 系统中，线程 1 和线程 2 都可以先将它们的写入排入队列，然后在这两个写入任一被写入内存之前，从内存中读取，从而两个读取都看到零。&lt;&#x2F;p&gt;
&lt;p&gt;这个例子看起来可能有些牵强，但在众所周知的同步算法中，使用两个同步变量确实会出现这种情况，比如 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dekker%27s_algorithm&quot;&gt;Dekker 算法&lt;&#x2F;a&gt; 或 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Peterson%27s_algorithm&quot;&gt;Peterson 算法&lt;&#x2F;a&gt;，以及一些临时方案。如果一个线程没有看到另一个线程的所有写入，这些算法就会失效。&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;在TSO（Total Store Order）模型中，允许每个线程维护自己的“写入队列”（store buffer），写操作首先进入这个队列，而不是立即刷新到主内存。当线程执行读取操作时，读取操作从主内存中读取数据（除非读取的是自己写入队列中尚未提交的地址），而其他线程看不到这些写入队列中的写入，直到它们被刷新到主内存。
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;线程1写入x=1，然后读取y到r1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;线程2写入y=1，然后读取x到r2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;在顺序一致性很严格的模型下，写操作会严格按程序顺序，被全局看到，因此不可能同时看到r1=0且r2=0，因为写入x或y的一方必定先被看到。
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;但是在TSO模型下，情况不同：
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;线程1写x=1，这个写入被放到线程1自己的写入缓冲区（store buffer）里，还没刷入主内存。
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;线程2写y=1，同样放到线程2自己的写入缓冲区里，尚未刷入主内存。
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;线程1读取y，此时y还未被线程2刷入主内存，线程1从主内存读取到的是初始值0（旧值），因为看不到对方的写缓冲区。
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;线程2读取x，情况同理，也是读到主内存中的旧值0。
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;由于两个线程都在读取中看不到对方的写入，产生了r1=0且r2=0的结果。
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;总结来说，写入缓冲区的存在和刷新延迟，是允许读操作“看到旧值”的关键原因。这导致了程序表现出在顺序一致模型下不可能出现的结果。
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;写入操作：先进入每个线程私有的写入缓冲区（store buffer），暂时不直接写入主内存。写入缓冲区中的内容会按照顺序缓慢且依次地刷新到主内存。
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;读取操作：通常直接从主内存读取数据，但如果读取的地址在该线程的写入缓冲区中存在未刷新到主内存的写入，读取操作会先从自己的写入缓冲区取最新值（即“写后读”保障），否则就从主内存读取。
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;换句话说：
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;写入操作先排队（进入写缓冲区），可能“延迟”对其他线程可见。
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;读取操作不排队，直接读取内存的最新状态或者自己的写缓冲区（当有对应未写入主内存的写入时）。
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;为了修复依赖更强内存顺序的算法，非顺序一致性硬件提供了称为内存屏障（或栅栏，memory barriers&#x2F;fences）的显式指令，用于控制顺序。我们可以添加内存屏障，确保每个线程在开始读取之前先将之前的写入刷新到内存：&lt;&#x2F;p&gt;
&lt;div style=&quot;display: flex; justify-content: space-between; font-family: monospace; white-space: pre; width: 400px;&quot;&gt;
  &lt;div&gt;
&#x2F;&#x2F; Thread 1
x = 1
barrier
r1 = y
  &lt;&#x2F;div&gt;
  &lt;div&gt;
&#x2F;&#x2F; Thread 2
y = 1
barrier
r2 = x
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;加入内存屏障后，r1 = 0，r2 = 0 再次变得不可能，Dekker 算法或 Peterson 算法也将能够正确工作。内存屏障有很多种类，它们的具体细节因系统而异，超出了本文的讨论范围。重点是，内存屏障的存在为程序员或语言实现者提供了一种方式，使得在程序的关键时刻能够强制执行顺序一致的行为。&lt;&#x2F;p&gt;
&lt;p&gt;最后举一个例子，说明为什么该模型被称为总存储顺序（total store order）。在该模型中，有本地写入队列，但读取路径上没有缓存。一旦写入到达主内存，所有处理器不仅会同意该值已经存在，还会就它相对于其他处理器写入何时到达达成一致。考虑如下试金石测试：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;试金石测试：独立写入的独立读取（IRIW）&lt;&#x2F;em&gt;&lt;br&gt;
这个程序是否能观察到 r1 = 1, r2 = 0, r3 = 1, r4 = 0？&lt;br&gt;
（线程3和线程4能否看到 x 和 y 按不同顺序变化？）
&lt;&#x2F;p&gt;
&lt;div style=&quot;display: flex; justify-content: space-between; font-family: monospace; white-space: pre; width: 700px;&quot;&gt;
  &lt;div&gt;
&#x2F;&#x2F; Thread 1
x = 1
  &lt;&#x2F;div&gt;
  &lt;div&gt;
&#x2F;&#x2F; Thread 2
y = 1
  &lt;&#x2F;div&gt;
  &lt;div&gt;
&#x2F;&#x2F; Thread 3
r1 = x
r2 = y
  &lt;&#x2F;div&gt;
  &lt;div&gt;
&#x2F;&#x2F; Thread 4
r3 = y
r4 = x
  &lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;在顺序一致性硬件上：不可能。&lt;br&gt;
在 x86（或其他 TSO）上：不可能。&lt;&#x2F;p&gt;
&lt;p&gt;如果线程3先看到 x 的变化再看到 y 的变化，线程4能否先看到 y 的变化再看到 x 的变化？对于 x86 和其他 TSO 机器，答案是否定的：存在一个覆盖所有写入到主内存的总顺序，并且所有处理器同意这个顺序，不过每个处理器对于自己写入达到主内存之前的情况有所不同。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-path-to-x86-tso-tong-xiang-x86-tso-de-lu-jing&quot;&gt;The Path to x86-TSO(通向 x86-TSO 的路径)&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-path-to-x86-tso-tong-xiang-x86-tso-de-lu-jing&quot; aria-label=&quot;Anchor link for: the-path-to-x86-tso-tong-xiang-x86-tso-de-lu-jing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;x86-TSO 模型看起来相当简洁，但通向它的道路充满了障碍和错误的转折。在1990年代，第一批 x86 多处理器的手册几乎没有提及硬件所提供的内存模型。&lt;&#x2F;p&gt;
&lt;p&gt;举一个问题的例子，Plan 9 是最早在 x86 上运行的真正多处理器操作系统之一（没有全局内核锁）。在1997年移植到多处理器 Pentium Pro 时，开发者遇到了意外行为，归结到写队列的试金石测试。一段细微的同步代码假设 r1 = 0，r2 = 0 不可能发生，但事实却发生了。更糟糕的是，Intel 的手册对内存模型的细节描述含糊不清。&lt;&#x2F;p&gt;
&lt;p&gt;针对邮件列表中提出的“与其信任硬件设计者按照我们的预期行事，不如对锁保持保守态度”的建议，Plan 9 的一位开发者很好地&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20091124045026&#x2F;http:&#x2F;&#x2F;9fans.net&#x2F;archive&#x2F;1997&#x2F;04&#x2F;76&quot;&gt;解释了这个问题&lt;&#x2F;a&gt;：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;我完全同意。我们在多处理器中将遇到更加宽松的排序问题。问题是，硬件设计者认为什么是保守？在锁定区段的开始和结束处强制执行互斥锁对我来说似乎相当保守，但显然我想象力不够。专业手册对描述缓存及其保持一致性的机制非常详尽，但似乎对执行顺序或读取顺序的细节不怎么关心。事实是，我们无法判断自己是否足够保守。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;在讨论过程中，Intel的一位架构师做了一个非正式的内存模型解释，指出理论上即使是多处理器486和Pentium系统也可能产生 r1 = 0，r2 = 0 的结果，而Pentium Pro只是因为具有更大的流水线和写入队列，更频繁地暴露了这种行为。&lt;&#x2F;p&gt;
&lt;p&gt;Intel 的架构师还写道：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;粗略来说，这意味着系统中任何一个处理器发起的事件顺序，在其他处理器观察时，总是相同的。然而，不同的观察者允许对来自两个或多个处理器事件交错的顺序存在分歧。
未来的 Intel 处理器将实现相同的内存排序模型。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;“不同观察者允许对两个或更多处理器事件交错顺序存在分歧”的说法，是指对 IRIW 试金石测试的答案在 x86 上可以是“是”，尽管在前面章节中我们看到 x86 的答案是否定的。这是怎么回事呢？&lt;&#x2F;p&gt;
&lt;p&gt;答案似乎是，Intel 处理器实际上从未对该试金石测试的结果给出过“是”的回答，但当时 Intel 的架构师们不愿对未来的处理器做出任何保证。架构手册中极少的说明几乎没有任何保障，使得针对这些不确定性进行编程非常困难。&lt;&#x2F;p&gt;
&lt;p&gt;Plan 9 的讨论并非孤立事件。Linux 内核开发者们在他们的邮件列表上花费了数百条消息，&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;lkml.org&#x2F;lkml&#x2F;1999&#x2F;11&#x2F;20&#x2F;76&quot;&gt;起始于1999年11月底&lt;&#x2F;a&gt;，围绕 Intel 处理器提供的保证陷入了类似的困惑。&lt;&#x2F;p&gt;
&lt;p&gt;针对随后的十年里越来越多的人遇到这些困难，Intel 的一组架构师承担了撰写关于处理器行为的有用保障的任务，既包括当前处理器也包括未来处理器。第一个成果是2007年8月发布的&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;www.cs.cmu.edu&#x2F;~410-f10&#x2F;doc&#x2F;Intel_Reordering_318147.pdf&quot;&gt;《Intel 64 Architecture Memory Ordering White Paper》&lt;&#x2F;a&gt;，旨在“为软件编写者提供对不同内存访问指令序列可能产生的结果的清晰理解”。AMD 同年晚些时候发布了类似的描述，见 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;courses.cs.washington.edu&#x2F;courses&#x2F;cse351&#x2F;12wi&#x2F;supp-docs&#x2F;AMD%20Vol%201.pdf&quot;&gt;AMD64 Architecture Programmer’s Manual revision 3.14&lt;&#x2F;a&gt;。这些描述基于一个称为“总锁顺序 + 因果一致性”（TLO+CC）的模型，该模型故意比 TSO 弱一些。在公开演讲中，Intel 架构师表示 TLO+CC 是“满足要求但不更强”。特别是，该模型保留了 x86 处理器在 IRIW 试金石测试中回答“是”的权利。不幸的是，内存屏障的定义&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;web.archive.org&#x2F;web&#x2F;20080512021617&#x2F;http:&#x2F;&#x2F;blogs.sun.com&#x2F;dave&#x2F;entry&#x2F;java_memory_model_concerns_on&quot;&gt;不够严格&lt;&#x2F;a&gt;，无法重新建立顺序一致的内存语义，即使在每条指令后都设置了屏障。更糟糕的是，研究人员还观察到实际的 Intel x86 硬件违反了 TLO+CC 模型。以下是一个例子：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Litmus 测试: n5&lt;&#x2F;em&gt;&lt;br&gt;
这个程序会出现 &lt;code&gt;r1 = 2, r2 = 1&lt;&#x2F;code&gt;?&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;&#x2F;&#x2F; Thread 1       &#x2F;&#x2F; Thread 2
x = 1             x = 2
r1 = x            r2 = x
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On sequentially consistent hardware: no.&lt;br&gt;
On x86 specification (2008): &lt;em&gt;yes!&lt;&#x2F;em&gt;&lt;br&gt;
On actual x86 hardware: no.&lt;br&gt;
On x86 TSO model: no. (Example from x86-TSO paper.)&lt;&#x2F;p&gt;
&lt;p&gt;为了解决这些问题，Owens 等人基于早期的 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;sparcv8.pdf&quot;&gt;SPARCv8 TSO 模型&lt;&#x2F;a&gt; 提出了 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;~pes20&#x2F;weakmemory&#x2F;x86tso-paper.tphols.pdf&quot;&gt;x86-TSO 模型&lt;&#x2F;a&gt;。当时他们宣称，“据我们所知，x86-TSO 是健全的，足够强大以支持上述编程，并且与厂商的意图大体一致。”几个月后，Intel 和 AMD 发布了新的手册，广泛采用了该模型。&lt;&#x2F;p&gt;
&lt;p&gt;看起来所有 Intel 处理器从一开始确实都实现了 x86-TSO，尽管 Intel 直到十年后才决定正式采纳它。回顾来看，很明显 Intel 和 AMD 的架构师当时正努力寻找一种内存模型，既能为未来处理器优化留下空间，又能为编译器开发者和汇编语言程序员提供有用的保障。“满足需求但不超强”是一种难以平衡的操作。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;arm-power-relaxed-memory-model-arm-power-song-san-nei-cun-mo-xing&quot;&gt;ARM&#x2F;POWER Relaxed Memory Model(ARM&#x2F;POWER 松散内存模型)&lt;a class=&quot;zola-anchor&quot; href=&quot;#arm-power-relaxed-memory-model-arm-power-song-san-nei-cun-mo-xing&quot; aria-label=&quot;Anchor link for: arm-power-relaxed-memory-model-arm-power-song-san-nei-cun-mo-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;现在让我们看看一种更加宽松的内存模型，即 ARM 和 POWER 处理器所采用的模型。在实现层面上，这两个系统有许多不同之处，但保证的内存一致性模型大致相似，并且比 x86-TSO 甚至 x86-TLO+CC 要弱得多。&lt;&#x2F;p&gt;
&lt;p&gt;ARM 和 POWER 系统的概念模型是，每个处理器从自己的完整内存副本中读取和写入数据，每次写操作独立传播到其他处理器，并且允许在写操作传播过程中重新排序。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;mem-weak@2x.png&quot; alt=&quot;The conceptual model for ARM and POWER systems&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;这里没有总的存储顺序。虽然未在图中显示，每个处理器也被允许推迟读取操作直到它需要结果：读取可以被推迟，直到后续的写操作完成。在这个松散模型中，到目前为止我们看到的所有 litmus 测试的答案都是“是的，这确实可能发生。”&lt;&#x2F;p&gt;
&lt;p&gt;对于原始的消息传递 litmus 测试，单个处理器对写操作的重新排序意味着线程1的写操作可能不会被其他线程以相同的顺序观察到：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Litmus 测试: 消息传递&lt;&#x2F;em&gt;&lt;br&gt;
这个程序会出现 &lt;code&gt;r1 = 1, r2 = 0&lt;&#x2F;code&gt; 的情况吗？&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;&#x2F;&#x2F; Thread 1        &#x2F;&#x2F; Thread 2
x = 1              r1 = y
y = 1              r2 = x
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在顺序一致的硬件上：不可能。&lt;br&gt;
在 x86（或其他 TSO）上：不可能。&lt;br&gt;
在 ARM&#x2F;POWER 上：可能！&lt;&#x2F;p&gt;
&lt;p&gt;在 ARM&#x2F;POWER 模型中，我们可以认为线程1和线程2各自拥有自己独立的内存副本，写操作以任意顺序在这些内存之间传播。如果线程1的内存先将 y 的更新发送给线程2，再发送 x 的更新，而线程2在这两次更新之间执行，那么它确实会看到结果 r1 = 1，r2 = 0。&lt;&#x2F;p&gt;
&lt;p&gt;这一结果表明，ARM&#x2F;POWER 内存模型比 TSO 更宽松：它对硬件的要求更少。ARM&#x2F;POWER 模型仍然允许 TSO 所允许的那种类型的重新排序。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Litmus 测试: 写缓冲&lt;&#x2F;em&gt;&lt;br&gt;
这个程序会出现 &lt;code&gt;r1 = 0, r2 = 0 &lt;&#x2F;code&gt;的情况吗？&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;&#x2F;&#x2F; Thread 1        &#x2F;&#x2F; Thread 2
x = 1              y = 1
r1 = y             r2 = x
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在顺序一致的硬件上：不可能。&lt;br&gt;
在 x86（或其他 TSO）上：可能！&lt;br&gt;
在 ARM&#x2F;POWER 上：可能！&lt;&#x2F;p&gt;
&lt;p&gt;在 ARM&#x2F;POWER 上，对 x 和 y 的写操作可能已写入到本地内存，但在对方线程进行读取时还未传播出去。&lt;&#x2F;p&gt;
&lt;p&gt;下面是展示 x86 拥有全序存储顺序含义的一个 Litmus 测试：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Litmus 测试：独立写的独立读 (IRIW)&lt;&#x2F;em&gt;&lt;br&gt;
这个程序能否看到 r1 = 1, r2 = 0, r3 = 1, r4 = 0？
（线程 3 和 线程 4 会看到 x 和 y 的变化顺序不同吗？）&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;
&#x2F;&#x2F; Thread 1        &#x2F;&#x2F; Thread 2      &#x2F;&#x2F; Thread 3        &#x2F;&#x2F; Thread 4
x = 1              y = 1            r1 = x              r3 = y
                                    r2 = y              r4 = x
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在顺序一致的硬件上：不可能。&lt;br&gt;
在 x86（或其他 TSO）上：不可能。&lt;br&gt;
在 ARM&#x2F;POWER 上：可能！&lt;&#x2F;p&gt;
&lt;p&gt;在 ARM&#x2F;POWER 上，不同的线程可能以不同的顺序了解到不同的写操作。它们不保证对到达主内存的写操作有一个总的顺序一致性，因此线程 3 可能会先看到 x 的变化，再看到 y 的变化，而线程 4 则可能先看到 y 的变化，再看到 x 的变化。&lt;&#x2F;p&gt;
&lt;p&gt;作为另一个例子，ARM&#x2F;POWER 系统具有可见的缓冲或内存读取（load）的重排序，如下述 litmus 测试所示：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Litmus 测试：加载缓冲&lt;&#x2F;em&gt;&lt;br&gt;
这个程序能否出现 &lt;code&gt;r1 = 1, r2 = 1&lt;&#x2F;code&gt;？&lt;br&gt;
（每个线程的读取是否可能发生在另一个线程的写入之后？）&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;&#x2F;&#x2F; 线程 1          &#x2F;&#x2F; 线程 2
r1 = x             r2 = y
y = 1              x = 1
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在顺序一致的硬件上：不可能。&lt;br&gt;
在 x86（或其他 TSO）上：不可能。&lt;br&gt;
在 ARM&#x2F;POWER 上：可能！&lt;&#x2F;p&gt;
&lt;p&gt;任何顺序一致的交织执行必须以线程1的 r1 = x 或线程2的 r2 = y 开始。那个读取操作必须看到一个零，从而使得结果 r1 = 1，r2 = 1 不可能出现。然而，在 ARM&#x2F;POWER 的内存模型中，处理器允许延迟读取，直到指令流中后面的写操作执行之后，从而使得 y = 1 和 x = 1 在两个读取之前先执行。&lt;&#x2F;p&gt;
&lt;p&gt;尽管 ARM 和 POWER 内存模型都允许这种结果，但 Maranget 等人于 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;~pes20&#x2F;ppc-supplemental&#x2F;test7.pdf&quot;&gt;2012 年的报告&lt;&#x2F;a&gt;显示，这种现象仅能在 ARM 系统上通过实验证明重现，而在 POWER 上则从未出现过。在这里，模型与现实之间的差异再次显现出来，就如我们之前研究 Intel x86 时发现的那样：实现比技术规范更强的硬件模型会促使软件依赖这种更强的行为，这意味着未来较弱的硬件无论是否符合规范，都可能导致程序出错。&lt;&#x2F;p&gt;
&lt;p&gt;像 TSO 系统一样，ARM 和 POWER 也有屏障（barriers），我们可以将其插入到上述示例中以强制顺序一致的行为。但显而易见的问题是，没有屏障的 ARM&#x2F;POWER 是否会排除任何行为？对任何 litmus 测试的回答都可能是“不会，绝不可能”，但当我们关注单个内存位置时，答案是肯定的。&lt;&#x2F;p&gt;
&lt;p&gt;以下是一个即使在 ARM 和 POWER 上也不可能发生的 litmus 测试：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Litmus 测试：一致性&lt;&#x2F;em&gt;&lt;br&gt;
这个程序能否出现 &lt;code&gt;r1 = 1, r2 = 2, r3 = 2, r4 = 1&lt;&#x2F;code&gt;？&lt;br&gt;
（线程 3 是否可能在看到 x = 2 之前先看到 x = 1，而线程 4 则相反？）&lt;&#x2F;p&gt;
&lt;pre&gt;&lt;code&gt;&#x2F;&#x2F; 线程 1          &#x2F;&#x2F; 线程 2          &#x2F;&#x2F; 线程 3          &#x2F;&#x2F; 线程 4
x = 1              x = 2              r1 = x            r3 = x
                                      r2 = x            r4 = x
&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在顺序一致的硬件上：不可能。&lt;br&gt;
在 x86（或其他 TSO）上：不可能。&lt;br&gt;
在 ARM&#x2F;POWER 上：不可能。&lt;&#x2F;p&gt;
&lt;p&gt;这个 litmus 测试类似于之前的例子，但现在两个线程都写入同一个变量 x，而不是两个不同的变量 x 和 y。线程 1 和 线程 2 向 x 写入冲突的值 1 和 2，同时线程 3 和线程 4 都读取两次 x。如果线程 3 看到 x = 1 被 x = 2 覆盖，线程 4 会看到相反的情况吗？&lt;&#x2F;p&gt;
&lt;p&gt;答案是否定的，即使在 ARM&#x2F;POWER 上也是如此：系统中的线程必须就对单一内存位置的写操作达成一个总的顺序一致性。也就是说，线程必须就哪些写操作覆盖了其他写操作达成一致。这一属性称为一致性（coherence）。如果没有一致性属性，处理器要么会对内存的最终结果产生分歧，要么会报告某个内存位置的值在多个值之间来回切换，程序设计这样的系统将非常困难。&lt;&#x2F;p&gt;
&lt;p&gt;我故意省略了许多关于 ARM 和 POWER 弱内存模型的细节。想了解更多细节，可以参考 &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;~pes20&#x2F;papers&#x2F;topics.html#Power_and_ARM&quot;&gt;Peter Sewell 关于该主题的相关文章&lt;&#x2F;a&gt;。此外，ARMv8 通过使其成为“多复制原子性（multicopy atomic）”来&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.cl.cam.ac.uk&#x2F;~pes20&#x2F;armv8-mca&#x2F;armv8-mca-draft.pdf&quot;&gt;加强了内存模型&lt;&#x2F;a&gt;，但我这里不会详细解释这个具体含义。&lt;&#x2F;p&gt;
&lt;p&gt;有两个重要的点需要注意。首先，这个话题涉及大量非常微妙的问题，是学术界经过十多年非常执着和聪明的研究人员深入探讨的结果。我自己也不能声称完全理解这些内容。这并不是我们期望向普通程序员解释的，也不是我们能在调试普通程序时轻易掌握的知识。其次，允许的行为和实际观察到的行为之间的差距会带来未来的不幸惊喜。如果当前硬件没有展示出允许行为的全部范围——尤其当我们很难推断什么行为是被允许时——那么不可避免地会出现一些程序，它们意外地依赖于硬件实际上更严格的行为。如果新芯片在行为上的限制更少，而新行为又在技术上被硬件内存模型允许，这导致了程序被破坏——这从技术上讲是硬件模型的问题，但对程序员来说基本上是错误引起的，这几乎没有什么安慰。这绝不是一种理想的程序设计方式。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;weak-ordering-and-data-race-free-sequential-consistency-ruo-shun-xu-he-wu-shu-ju-jing-zheng-de-shun-xu-yi-zhi-xing&quot;&gt;Weak Ordering and Data-Race-Free Sequential Consistency(弱顺序和无数据竞争的顺序一致性)&lt;a class=&quot;zola-anchor&quot; href=&quot;#weak-ordering-and-data-race-free-sequential-consistency-ruo-shun-xu-he-wu-shu-ju-jing-zheng-de-shun-xu-yi-zhi-xing&quot; aria-label=&quot;Anchor link for: weak-ordering-and-data-race-free-sequential-consistency-ruo-shun-xu-he-wu-shu-ju-jing-zheng-de-shun-xu-yi-zhi-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;到现在，我希望你已经相信硬件细节是复杂且微妙的，不是每次写程序时都想去详细研究的东西。相反，更有帮助的是找到一些简便方法，比如“如果你遵循这些简单规则，你的程序只会产生像顺序一致交错执行那样的结果。”（我们讨论的仍然是硬件，所以我们还是在讨论单条汇编指令的交错执行。）&lt;&#x2F;p&gt;
&lt;p&gt;Sarita Adve 和 Mark Hill 在他们1990年的论文&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;http:&#x2F;&#x2F;citeseerx.ist.psu.edu&#x2F;viewdoc&#x2F;summary?doi=10.1.1.42.5567&quot;&gt;《Weak Ordering – A New Definition》&lt;&#x2F;a&gt;中提出了这种方法。他们将“弱有序”定义如下。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;假设一个同步模型是一组关于内存访问的约束，规定了同步操作如何以及何时进行。
当且仅当对遵守该同步模型的所有软件来说，硬件表现为顺序一致时，该硬件相对于该同步模型就是弱有序的。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;虽然他们的论文是关于捕捉当时硬件设计（而非 x86、ARM 和 POWER）的，但将讨论提升到具体设计之上的思路，使得这篇论文至今仍具参考价值。&lt;&#x2F;p&gt;
&lt;p&gt;我之前说过，“有效的优化不会改变有效程序的行为。”规则定义了“有效”的含义，然后任何硬件优化必须保持这些程序在顺序一致机器上的行为不变。当然，有趣的细节是规则本身，即定义程序何为有效的约束。&lt;&#x2F;p&gt;
&lt;p&gt;Adve 和 Hill 提出了一个同步模型，称为无数据竞争（data-race-free，DRF）。该模型假设硬件将内存同步操作与普通内存的读写操作分开。普通内存的读写操作可能在同步操作之间重新排序，但不能跨越同步操作移动。（也就是说，同步操作同时充当了重排序的屏障。）如果在所有理想化的顺序一致执行中，任意两个线程对同一内存位置的普通内存访问要么都是读操作，要么被同步操作隔开，保证一个操作一定先发生，那么该程序被称为无数据竞争。&lt;&#x2F;p&gt;
&lt;p&gt;让我们来看一些例子，取自 Adve 和 Hill 的论文（为展示重新绘制）。这里有一个单线程，先执行对变量 x 的写操作，接着读取同一个变量。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;mem-adve-1@2x.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;垂直箭头标示了单个线程内的执行顺序：先进行写操作，然后是读操作。这个程序中不存在竞态条件，因为所有操作都在同一个线程中。&lt;&#x2F;p&gt;
&lt;p&gt;相比之下，下面这个两线程程序中存在竞态条件：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;mem-adve-2@2x.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;这里，线程 2 对变量 x 进行写操作，而没有与线程 1 进行协调。线程 2 的写操作与线程 1 的写操作和读操作都存在竞态条件。如果线程 2 是读取 x 而非写入，那么程序中只有一次竞态，即线程 1 的写操作与线程 2 的读操作之间的竞态。每一次竞态至少涉及一个写操作：两个不协调的读操作之间不存在竞态。&lt;&#x2F;p&gt;
&lt;p&gt;为了避免竞态，我们必须添加同步操作，迫使共享同步变量的不同线程间的操作有序进行。如果同步操作 S(a)（对变量 a 的同步操作，用虚线箭头标记）强制线程 2 的写操作在线程 1 操作完成后发生，那么竞态就被消除了：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;mem-adve-3@2x.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;现在，线程 2 的写操作不能与线程 1 的操作同时发生。&lt;&#x2F;p&gt;
&lt;p&gt;如果线程 2 只是进行读取操作，那么我们只需与线程 1 的写操作进行同步。两个读取操作仍然可以并发进行：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;mem-adve-4@2x.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;线程可以通过一系列同步操作来排序，甚至可以通过中间线程实现排序。这个程序没有竞态条件：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;mem-adve-5@2x.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;另一方面，仅仅使用同步变量并不能消除竞态条件：错误地使用同步变量也是可能的。这个程序确实存在竞态条件：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;mem-adve-6@2x.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;线程 2 的读取操作与其他线程的写入操作进行了正确的同步——它肯定发生在两者之后——但这两个写入操作本身并未同步。这个程序不是无数据竞态的。&lt;&#x2F;p&gt;
&lt;p&gt;Adve 和 Hill 提出了弱序（一种软件与硬件之间的“契约”），具体来说，就是如果软件避免了数据竞态，那么硬件表现得就好像它是顺序一致的，这比我们在前面章节中研究的模型更容易理解。但硬件如何满足这种契约呢？&lt;&#x2F;p&gt;
&lt;p&gt;Adve 和 Hill 证明了硬件是“由 DRF 弱序的”，意即硬件在执行无数据竞态程序时，好像按照顺序一致的顺序执行，只要满足某些最低要求。这里不打算详细展开细节，重点是 Adve 和 Hill 的论文之后，硬件设计者拥有一套由证明支持的“配方”：做这些事情，你即可断言你的硬件对于无数据竞态程序表现为顺序一致。实际上，大多数弱序硬件都是这样运行的，并且在实现同步操作时也假设如此。Adve 和 Hill 最初关注的是 VAX 架构，但显然 x86、ARM 和 POWER 也能满足这些约束。这个想法是系统保证无数据竞态程序的顺序一致性，这经常被缩写为 DRF-SC。&lt;&#x2F;p&gt;
&lt;p&gt;DRF-SC 标志着硬件内存模型的一个转折点，为硬件设计者和软件开发者（至少那些编写汇编语言的软件开发者）提供了清晰的策略。正如我们将在下一篇文章中看到的，更高级编程语言的内存模型问题并没有同样简明的答案。&lt;&#x2F;p&gt;
&lt;p&gt;本系列的下一篇文章将介绍编程语言内存模型（programming language memory models）。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zhi-xie&quot;&gt;致谢&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhi-xie&quot; aria-label=&quot;Anchor link for: zhi-xie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;这一系列文章得益于与我在谷歌有幸共事的一长串工程师们的讨论和反馈。在此向他们表示感谢。对于任何错误或不受欢迎的观点，我承担全部责任。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;research.swtch.com&#x2F;hwmm&quot;&gt;https:&#x2F;&#x2F;research.swtch.com&#x2F;hwmm&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | 不可变数据共享</title>
          <pubDate>Fri, 18 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-18-immutable-data-sharing/</link>
          <guid>https://inasa.dev/posts/25-04-18-immutable-data-sharing/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-18-immutable-data-sharing/">&lt;p&gt;在构建高性能 &lt;code&gt;Go&lt;&#x2F;code&gt; 应用程序时，一个常见的瓶颈是对共享数据的并发访问。传统的方法通常涉及使用互斥锁或通道来管理同步。虽然这些工具有效，但如果使用不当，可能会增加复杂性并引入隐蔽的错误。&lt;&#x2F;p&gt;
&lt;p&gt;一种强大的替代方案是不可变数据共享。通过不使用锁来保护数据，您可以设计系统，使得共享数据在创建后永远不会被更改。这最小化了争用并简化了对程序的推理。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wei-shen-me-xuan-ze-bu-ke-bian-shu-ju&quot;&gt;为什么选择不可变数据？&lt;a class=&quot;zola-anchor&quot; href=&quot;#wei-shen-me-xuan-ze-bu-ke-bian-shu-ju&quot; aria-label=&quot;Anchor link for: wei-shen-me-xuan-ze-bu-ke-bian-shu-ju&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;不可变性为并发程序带来了几个优势：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;无需锁：多个协程可以安全地读取不可变数据而无需同步。&lt;&#x2F;li&gt;
&lt;li&gt;更容易推理：如果数据不能改变，您可以避免整类竞态条件。&lt;&#x2F;li&gt;
&lt;li&gt;写时复制优化：您可以创建结构的新版本而不改变原始结构，这对于配置重新加载或版本控制状态非常有用。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;shi-ji-shi-li-gong-xiang-pei-zhi&quot;&gt;实际示例：共享配置&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-ji-shi-li-gong-xiang-pei-zhi&quot; aria-label=&quot;Anchor link for: shi-ji-shi-li-gong-xiang-pei-zhi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;假设你有一个长期运行的服务，它会定期从磁盘或远程源重新加载配置。多个 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 会读取此配置以进行决策。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bu-zou-1-ding-yi-config-jie-gou-ti&quot;&gt;步骤1：定义 Config 结构体&lt;a class=&quot;zola-anchor&quot; href=&quot;#bu-zou-1-ding-yi-config-jie-gou-ti&quot; aria-label=&quot;Anchor link for: bu-zou-1-ding-yi-config-jie-gou-ti&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; config.go
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Config&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;LogLevel&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;Timeout&lt;&#x2F;span&gt;  &lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Duration&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;Features&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-map z-go&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 这部分需要注意！
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;bu-zou-2-que-bao-shen-du-bu-ke-bian-xing&quot;&gt;步骤2：确保深度不可变性&lt;a class=&quot;zola-anchor&quot; href=&quot;#bu-zou-2-que-bao-shen-du-bu-ke-bian-xing&quot; aria-label=&quot;Anchor link for: bu-zou-2-que-bao-shen-du-bu-ke-bian-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;Go&lt;&#x2F;code&gt; 中的 &lt;code&gt;map&lt;&#x2F;code&gt; 和 &lt;code&gt;slice&lt;&#x2F;code&gt; 是引用类型。即使 &lt;code&gt;Config&lt;&#x2F;code&gt; 结构体本身没有被修改，也可能有人不小心修改了共享的 &lt;code&gt;map&lt;&#x2F;code&gt;。为防止这种情况，我们制作防御性拷贝：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;NewConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;logLevel&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;timeout&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Duration&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;features&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-map z-go&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Config&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;copiedFeatures&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword z-map z-go&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;features&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;v&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-go&quot;&gt;range&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;features&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;copiedFeatures&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;k&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;v&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;LogLevel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;logLevel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Timeout&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;  &lt;span class=&quot;z-variable z-other z-go&quot;&gt;timeout&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Features&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;copiedFeatures&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;现在，每个配置实例都是自包含的，且可以安全共享。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bu-zou-3-yuan-zi-jiao-huan&quot;&gt;步骤3：原子交换&lt;a class=&quot;zola-anchor&quot; href=&quot;#bu-zou-3-yuan-zi-jiao-huan&quot; aria-label=&quot;Anchor link for: bu-zou-3-yuan-zi-jiao-huan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;使用 &lt;code&gt;atomic.Value&lt;&#x2F;code&gt; 来存储并安全地更新当前配置。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;currentConfig&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;atomic&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;LoadInitialConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;cfg&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;NewConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;info&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Second&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-map z-go&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;beta&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;currentConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Store&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;cfg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;GetConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Config&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;currentConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Load&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;现在所有 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 都可以安全地调用 &lt;code&gt;GetConfig()&lt;&#x2F;code&gt;，无需加锁。当配置重新加载时，只需存储（&lt;code&gt;Store&lt;&#x2F;code&gt;）一个新的不可变副本。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bu-zou-4-zai-chu-li-han-shu-zhong-shi-yong&quot;&gt;步骤4：在处理函数中使用&lt;a class=&quot;zola-anchor&quot; href=&quot;#bu-zou-4-zai-chu-li-han-shu-zhong-shi-yong&quot; aria-label=&quot;Anchor link for: bu-zou-4-zai-chu-li-han-shu-zhong-shi-yong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;handler&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;w&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ResponseWriter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;r&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;cfg&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;GetConfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;cfg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Features&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;beta&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 启用 beta 路径
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 使用 cfg.Timeout、cfg.LogLevel 等
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;shi-ji-shi-li-bu-ke-bian-lu-you-biao&quot;&gt;实际示例：不可变路由表&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-ji-shi-li-bu-ke-bian-lu-you-biao&quot; aria-label=&quot;Anchor link for: shi-ji-shi-li-bu-ke-bian-lu-you-biao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;假设你正在构建一个轻量级的反向代理或 &lt;code&gt;API&lt;&#x2F;code&gt; 网关，必须根据路径或主机来路由传入的请求。路由表每秒被读取成千上万次，但只偶尔更新（例如，从配置文件或服务发现中）。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bu-zou-1-ding-yi-lu-you-jie-gou-ti&quot;&gt;步骤1：定义路由结构体&lt;a class=&quot;zola-anchor&quot; href=&quot;#bu-zou-1-ding-yi-lu-you-jie-gou-ti&quot; aria-label=&quot;Anchor link for: bu-zou-1-ding-yi-lu-you-jie-gou-ti&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Route&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;Path&lt;&#x2F;span&gt;    &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;Backend&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;RoutingTable&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;Routes&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Route&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;bu-zou-2-gou-jian-bu-ke-bian-ban-ben&quot;&gt;步骤2：构建不可变版本&lt;a class=&quot;zola-anchor&quot; href=&quot;#bu-zou-2-gou-jian-bu-ke-bian-ban-ben&quot; aria-label=&quot;Anchor link for: bu-zou-2-gou-jian-bu-ke-bian-ban-ben&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;为了确保不可变性，在构造新的路由表时，我们对路由切片进行深拷贝。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;NewRoutingTable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;routes&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Route&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;RoutingTable&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;copied&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Route&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;routes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;copy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;copied&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;routes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;RoutingTable&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Routes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;copied&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;bu-zou-3-yuan-zi-cun-chu&quot;&gt;步骤3：原子存储&lt;a class=&quot;zola-anchor&quot; href=&quot;#bu-zou-3-yuan-zi-cun-chu&quot; aria-label=&quot;Anchor link for: bu-zou-3-yuan-zi-cun-chu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;currentRoutes&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;atomic&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;RoutingTable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;LoadInitialRoutes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;table&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;NewRoutingTable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Route&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;api&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Backend&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;http:&#x2F;&#x2F;api.internal&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;admin&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Backend&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;http:&#x2F;&#x2F;admin.internal&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;currentRoutes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Store&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;table&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;GetRoutingTable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;RoutingTable&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;currentRoutes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Load&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;bu-zou-4-bing-fa-lu-you-qing-qiu&quot;&gt;步骤4：并发路由请求&lt;a class=&quot;zola-anchor&quot; href=&quot;#bu-zou-4-bing-fa-lu-you-qing-qiu&quot; aria-label=&quot;Anchor link for: bu-zou-4-bing-fa-lu-you-qing-qiu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;routeRequest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;path&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;table&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;GetRoutingTable&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;route&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-go&quot;&gt;range&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;table&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Routes&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;strings&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;HasPrefix&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;route&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Path&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;route&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Backend&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这样，路由逻辑可以在负载下安全扩展，且无需加锁开销。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;kuo-zhan-bu-ke-bian-lu-you-biao&quot;&gt;扩展不可变路由表&lt;a class=&quot;zola-anchor&quot; href=&quot;#kuo-zhan-bu-ke-bian-lu-you-biao&quot; aria-label=&quot;Anchor link for: kuo-zhan-bu-ke-bian-lu-you-biao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;随着系统的发展，路由表可能包含数百甚至数千条规则。每次微小的更改都重建和复制整个结构，可能变得不切实际。&lt;&#x2F;p&gt;
&lt;p&gt;下面介绍几种在保持不可变性优点的同时，演进该设计的方法。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;chang-jing-1-fen-duan-lu-you&quot;&gt;场景1：分段路由&lt;a class=&quot;zola-anchor&quot; href=&quot;#chang-jing-1-fen-duan-lu-you&quot; aria-label=&quot;Anchor link for: chang-jing-1-fen-duan-lu-you&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;假设有一个多租户系统，每个客户都有自己的一套路由规则。与其使用一大段路由，不如将它们拆分成一个映射：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;MultiTable&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;Tables&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-map z-go&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;RoutingTable&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; key 是租户ID
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;如果只有客户 &quot;acme&quot; 更新他们的规则，你只需复制那一段并更新映射。然后你原子交换整个映射的新版本。其他租户继续使用它们现有的、未被修改的路由表。&lt;&#x2F;p&gt;
&lt;p&gt;这种方法降低了内存压力，加快了更新速度，同时不失去不可变性的优势。它还实现了影响范围隔离：一个段中的错误规则不会影响其他段。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;chang-jing-2-suo-yin-lu-you-biao&quot;&gt;场景2：索引路由表&lt;a class=&quot;zola-anchor&quot; href=&quot;#chang-jing-2-suo-yin-lu-you-biao&quot; aria-label=&quot;Anchor link for: chang-jing-2-suo-yin-lu-you-biao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;假设你的路由器通过精确路径匹配，且查找速度至关重要。你可以使用 &lt;code&gt;map[string]RouteHandler&lt;&#x2F;code&gt; 作为索引：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;RouteIndex&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-map z-go&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;RouteHandler&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;当添加新路径时，克隆当前的映射，添加新路由，并发布新版本。由于映射是浅拷贝，对于中等数量的路由，这种方式是快速的。读取是常数时间，更新也高效，因为只有结构的一小部分发生变化。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;chang-jing-3-hun-he-fen-jie-duan-geng-xin-he-fa-bu&quot;&gt;场景3：混合分阶段更新和发布&lt;a class=&quot;zola-anchor&quot; href=&quot;#chang-jing-3-hun-he-fen-jie-duan-geng-xin-he-fa-bu&quot; aria-label=&quot;Anchor link for: chang-jing-3-hun-he-fen-jie-duan-geng-xin-he-fa-bu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;假设你正在进行批量更新——比如从数据库读取数百条路由。你可以保留一个可变的暂存区，而不是直接在线重建：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;mu&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;sync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Mutex&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;stagingRoutes&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Route&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;可以在暂存中以互斥方式加载和操作数据，然后转换为不可变 &lt;code&gt;RoutingTable&lt;&#x2F;code&gt; 并以原子方式存储。这样，就可以安全地准备复杂的更改，而不会锁定读取器或影响实时流量。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ji-zhun-ce-shi-ying-xiang&quot;&gt;基准测试影响&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-zhun-ce-shi-ying-xiang&quot; aria-label=&quot;Anchor link for: ji-zhun-ce-shi-ying-xiang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;在现实系统中，对不可变数据共享进行基准测试很难以通用且有意义的方式进行。诸如结构大小、读写比例和内存布局等因素都会对结果产生重大影响。&lt;&#x2F;p&gt;
&lt;p&gt;与其在这里展示人为的基准测试，推荐查看&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;goperf.dev&#x2F;01-common-patterns&#x2F;atomic-ops&#x2F;#benchmarking-impact&quot;&gt;原子操作与同步原语&lt;&#x2F;a&gt;一文中的测试结果。那些基准测试清楚地展示了使用 &lt;code&gt;atomic.Value&lt;&#x2F;code&gt; 相较于传统的同步原语（如 &lt;code&gt;sync.RWMutex&lt;&#x2F;code&gt;）在性能上的潜在优势，特别是在高度并发的读场景中。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;he-shi-shi-yong-ci-mo-shi&quot;&gt;何时使用此模式&lt;a class=&quot;zola-anchor&quot; href=&quot;#he-shi-shi-yong-ci-mo-shi&quot; aria-label=&quot;Anchor link for: he-shi-shi-yong-ci-mo-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;不可变数据共享的理想场景包括：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;数据以读操作为主、写操作较少（例如配置、功能标志、全局映射）。这种情况下，创建不可变新版本的成本可以通过大量读取来摊销，避免锁机制还能提升性能。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;希望在不牺牲安全性的前提下尽量减少锁的使用。通过共享只读数据，可以消除对互斥锁或协调机制的需求，降低死锁或竞态条件的风险。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;可以容忍更新和读取之间存在轻微延迟（最终一致性）。由于数据更新与读取者之间没有协调，所有协程看到新版数据前可能会有短暂延迟。如果对精确时序要求不高，这种权衡能简化并发模型。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;它不太适合需要跨多条数据进行事务性更新或频繁发生更新的场景。在这些情况下，重复复制的成本或协调缺失可能会抵消其带来的好处。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;goperf.dev&#x2F;01-common-patterns&#x2F;immutable-data&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | 高效的上下文管理</title>
          <pubDate>Thu, 17 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-17-efficient-context-management/</link>
          <guid>https://inasa.dev/posts/25-04-17-efficient-context-management/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-17-efficient-context-management/">&lt;p&gt;无论是在处理 &lt;code&gt;HTTP&lt;&#x2F;code&gt; 请求、协调工作协程，还是查询外部服务，通常都需要取消正在进行的操作或强制执行执行期限。&lt;code&gt;Go&lt;&#x2F;code&gt; 的 &lt;code&gt;context&lt;&#x2F;code&gt; 包正是为此设计的——它提供了一种一致且线程安全的方式来管理操作的生命周期、传递元数据，并确保资源能够及时清理。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wei-shen-me-shang-xia-wen-hen-zhong-yao&quot;&gt;为什么上下文很重要&lt;a class=&quot;zola-anchor&quot; href=&quot;#wei-shen-me-shang-xia-wen-hen-zhong-yao&quot; aria-label=&quot;Anchor link for: wei-shen-me-shang-xia-wen-hen-zhong-yao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;Go&lt;&#x2F;code&gt; 提供了两个基本的上下文构造函数：&lt;code&gt;context.Background()&lt;&#x2F;code&gt; 和 &lt;code&gt;context.TODO()&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;context.Background()&lt;&#x2F;code&gt; 是根上下文，通常用于应用程序的顶层——例如在 &lt;code&gt;main&lt;&#x2F;code&gt;、&lt;code&gt;init&lt;&#x2F;code&gt; 函数中，或在当没有可用的现有上下文使用的服务器设置时。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;context.TODO()&lt;&#x2F;code&gt; 是一个占位符，当不清楚使用哪个上下文，或周围代码尚未完全配备上下文传播时使用。提醒开发者上下文逻辑需要在之后补充完整。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;Go&lt;&#x2F;code&gt; 中的 &lt;code&gt;context&lt;&#x2F;code&gt; 包设计用来携带截止时间、取消信号，以及跨 API 边界的其他请求范围内的值。它在需要协调和干净取消操作的并发程序中特别有用。&lt;&#x2F;p&gt;
&lt;p&gt;典型的上下文工作流程从程序或请求的入口点开始——如 &lt;code&gt;HTTP&lt;&#x2F;code&gt; 处理器、&lt;code&gt;main&lt;&#x2F;code&gt; 函数或 &lt;code&gt;RPC&lt;&#x2F;code&gt; 服务器。从这里，使用 &lt;code&gt;context.Background()&lt;&#x2F;code&gt; 或 &lt;code&gt;context.TODO()&lt;&#x2F;code&gt; 创建一个基础上下文。这个上下文随后可以通过以下构造函数进行扩展：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;context.WithCancel(parent)&lt;&#x2F;code&gt; 创建一个可取消的上下文。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;context.WithTimeout(parent, duration)&lt;&#x2F;code&gt; 在特定时间后自动取消。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;context.WithDeadline(parent, time)&lt;&#x2F;code&gt; 在固定时间点取消。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;context.WithValue(parent, key, value)&lt;&#x2F;code&gt; 附加请求范围的数据。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;以上每个函数都会返回一个包装其父上下文的新上下文。取消信号、截止时间和数据会自动向调用栈下方传播。当上下文被取消——无论是手动取消还是超时取消——任何监听 &lt;code&gt;&amp;lt;-ctx.Done()&lt;&#x2F;code&gt; 的 &lt;code&gt;goroutine&lt;&#x2F;code&gt; 或函数会立即收到通知。&lt;&#x2F;p&gt;
&lt;p&gt;通过在函数参数中显式传递上下文，可以避免隐藏的依赖关系，并获得对并发操作执行生命周期的细粒度控制。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shang-xia-wen-shi-yong-de-shi-yong-shi-li&quot;&gt;上下文使用的实用示例&lt;a class=&quot;zola-anchor&quot; href=&quot;#shang-xia-wen-shi-yong-de-shi-yong-shi-li&quot; aria-label=&quot;Anchor link for: shang-xia-wen-shi-yong-de-shi-yong-shi-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;以下示例展示了 &lt;code&gt;context.Context&lt;&#x2F;code&gt; 如何在各种真实场景中实现更好的控制、可观察性和资源管理。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;http-fu-wu-qi-qing-qiu-qu-xiao&quot;&gt;HTTP 服务器请求取消&lt;a class=&quot;zola-anchor&quot; href=&quot;#http-fu-wu-qi-qing-qiu-qu-xiao&quot; aria-label=&quot;Anchor link for: http-fu-wu-qi-qing-qiu-qu-xiao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;上下文帮助优雅地处理客户端提前断开连接时的取消操作。&lt;code&gt;Go&lt;&#x2F;code&gt; 中每个传入的 &lt;code&gt;HTTP&lt;&#x2F;code&gt; 请求都携带一个上下文，当客户端关闭连接时，该上下文会被取消。通过检查 &lt;code&gt;&amp;lt;-ctx.Done()&lt;&#x2F;code&gt;，可以提前退出，避免执行不必要的工作：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;handler&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;w&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ResponseWriter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;req&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;req&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;select&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;case&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;After&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;5&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Second&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fprintln&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;w&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Response after delay&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;case&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Done&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Client disconnected&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在这个示例中，处理器等待模拟延迟或取消事件。如果客户端在超时前关闭连接，&lt;code&gt;ctx.Done()&lt;&#x2F;code&gt; 会被触发，允许处理器在不写入响应的情况下进行清理操作。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;dai-chao-shi-de-shu-ju-ku-cao-zuo&quot;&gt;带超时的数据库操作&lt;a class=&quot;zola-anchor&quot; href=&quot;#dai-chao-shi-de-shu-ju-ku-cao-zuo&quot; aria-label=&quot;Anchor link for: dai-chao-shi-de-shu-ju-ku-cao-zuo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;上下文提供了一种简单的方法来对数据库查询强制执行超时。许多驱动支持 &lt;code&gt;QueryContext&lt;&#x2F;code&gt; 或类似的方法，这些方法尊重取消操作：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;cancel&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;WithTimeout&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;time&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Second&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;defer&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;cancel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;rows&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;db&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;QueryContext&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;SELECT * FROM users&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fatal&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;err&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;defer&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;rows&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Close&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在这种情况下，如果数据库在两秒内没有响应，上下文会自动取消。查询会被中止，应用程序不会无限期挂起。这有助于管理资源，避免在高负载环境中出现连锁故障。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fen-bu-shi-zhui-zong-zhong-qing-qiu-id-de-chuan-bo&quot;&gt;分布式追踪中请求 ID 的传播&lt;a class=&quot;zola-anchor&quot; href=&quot;#fen-bu-shi-zhui-zong-zhong-qing-qiu-id-de-chuan-bo&quot; aria-label=&quot;Anchor link for: fen-bu-shi-zhui-zong-zhong-qing-qiu-id-de-chuan-bo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;上下文允许在分布式系统的不同层之间传递追踪信息。例如，在边缘生成的请求 &lt;code&gt;ID&lt;&#x2F;code&gt; 可以附加到上下文中，并在整个应用程序中记录或使用：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;WithValue&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;requestID&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;12345&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-function z-go&quot;&gt;handleRequest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;handleRequest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Handling request with ID: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%v&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;requestID&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在此示例中，&lt;code&gt;WithValue&lt;&#x2F;code&gt; 将请求 &lt;code&gt;ID&lt;&#x2F;code&gt; 附加到上下文中。函数 &lt;code&gt;handleRequest&lt;&#x2F;code&gt; 使用 &lt;code&gt;ctx.Value&lt;&#x2F;code&gt; 取出该值，实现了无须修改函数签名的情况下进行一致的日志记录和可观察性。这种方法在中间件、日志和追踪管道中很常见。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bing-fa-gong-zuo-xie-cheng-guan-li&quot;&gt;并发工作协程管理&lt;a class=&quot;zola-anchor&quot; href=&quot;#bing-fa-gong-zuo-xie-cheng-guan-li&quot; aria-label=&quot;Anchor link for: bing-fa-gong-zuo-xie-cheng-guan-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;上下文提供了对多个工作协程的控制。通过使用 &lt;code&gt;WithCancel&lt;&#x2F;code&gt;，你可以从一个中心点向所有工作协程传播停止信号：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;cancel&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;WithCancel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;10&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;++&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;go&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;worker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 在某个条件或信号触发后取消工作协程
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;cancel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;每个工作函数应该检查 &lt;code&gt;&amp;lt;-ctx.Done()&lt;&#x2F;code&gt;，并在上下文被取消时立即返回。这保持了系统的响应性，避免了悬挂的协程，并允许并行工作的优雅终止。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ming-ling-xing-gong-ju-zhong-de-you-ya-guan-bi&quot;&gt;命令行工具中的优雅关闭&lt;a class=&quot;zola-anchor&quot; href=&quot;#ming-ling-xing-gong-ju-zhong-de-you-ya-guan-bi&quot; aria-label=&quot;Anchor link for: ming-ling-xing-gong-ju-zhong-de-you-ya-guan-bi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;在命令行应用程序或长时间运行的后台进程中，上下文简化了操作系统信号的处理和优雅关闭：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;stop&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;signal&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;NotifyContext&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Background&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Interrupt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;defer&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;stop&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Done&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Shutting down...&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在此模式中，&lt;code&gt;signal.NotifyContext&lt;&#x2F;code&gt; 返回一个上下文，当接收到中断信号（例如 &lt;code&gt;Ctrl+C&lt;&#x2F;code&gt;）时，该上下文会自动取消。监听 &lt;code&gt;&amp;lt;-ctx.Done()&lt;&#x2F;code&gt; 允许应用程序执行清理操作并优雅退出，而不是突然终止。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;liu-shi-he-shi-shi-shu-ju-guan-dao&quot;&gt;流式和实时数据管道&lt;a class=&quot;zola-anchor&quot; href=&quot;#liu-shi-he-shi-shi-shu-ju-guan-dao&quot; aria-label=&quot;Anchor link for: liu-shi-he-shi-shi-shu-ju-guan-dao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;上下文非常适合协调流式系统中的读取者，比如 &lt;code&gt;Kafka&lt;&#x2F;code&gt; 消费者、&lt;code&gt;WebSocket&lt;&#x2F;code&gt; 读取器或自定义的发布&#x2F;订阅管道：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;streamData&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;ch&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword z-chan z-go&quot;&gt;chan&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;select&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;case&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Done&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;case&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;data&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-variable z-function z-go&quot;&gt;process&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;data&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在这里，该函数处理来自通道的传入数据。如果上下文被取消（例如在关闭或超时期间），循环将中断，协程干净地退出。这使系统对控制信号更具响应性，也更容易在负载下进行管理。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zhong-jian-jian-he-xian-liu&quot;&gt;中间件和限流&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhong-jian-jian-he-xian-liu&quot; aria-label=&quot;Anchor link for: zhong-jian-jian-he-xian-liu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;上下文通常用于中间件链中，以强制执行配额、追踪请求，或在各层之间传递限流决策。在典型的 &lt;code&gt;HTTP&lt;&#x2F;code&gt; 栈中，中间件可以基于自定义逻辑（例如基于 &lt;code&gt;IP&lt;&#x2F;code&gt; 的限速或用户配额检查）判断请求是否允许，并将该决定附加到上下文中，以便后续处理程序检查。&lt;&#x2F;p&gt;
&lt;p&gt;下面是一个简化示例，演示该机制如何工作：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;rateLimitMiddleware&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;next&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Handler&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Handler&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;HandlerFunc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;w&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ResponseWriter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;r&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 假设这是某些限流逻辑的结果
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;rateLimited&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;true&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 或根据逻辑设为 false
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 将结果嵌入到上下文中
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;WithValue&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;rateLimited&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;rateLimited&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 将更新后的上下文传递给下一个处理程序
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;next&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;ServeHTTP&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;w&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;WithContext&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在下游处理程序中，你可能会这样检查该值：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;handler&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;w&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;ResponseWriter&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;r&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;ctx&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;limited&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;ok&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;ctx&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Value&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;rateLimited&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;bool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;ok&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;limited&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Error&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;w&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Too many requests&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;http&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;StatusTooManyRequests&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Fprintln&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;w&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Request accepted&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这种模式避免了在中间件和处理程序之间共享状态的需要。相反，上下文充当一个轻量级通道，以安全且可组合的方式在请求管道的各层之间传递元数据。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ji-zhun-ce-shi-ying-xiang&quot;&gt;基准测试影响&lt;a class=&quot;zola-anchor&quot; href=&quot;#ji-zhun-ce-shi-ying-xiang&quot; aria-label=&quot;Anchor link for: ji-zhun-ce-shi-ying-xiang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;在使用 &lt;code&gt;context.Context&lt;&#x2F;code&gt; 时，通常不会直接在原始性能方面进行基准测试。它的真正好处在于提高响应性，避免无谓的计算浪费，以及支持干净的取消操作。其影响体现在减少内存泄漏、避免僵尸协程以及更可预测的资源生命周期 —— 这些指标最好通过真实环境中的性能分析和可观测性工具来观察。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shang-xia-wen-shi-yong-de-zui-jia-shi-jian&quot;&gt;上下文使用的最佳实践&lt;a class=&quot;zola-anchor&quot; href=&quot;#shang-xia-wen-shi-yong-de-zui-jia-shi-jian&quot; aria-label=&quot;Anchor link for: shang-xia-wen-shi-yong-de-zui-jia-shi-jian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;始终显式传递 &lt;code&gt;context.Context&lt;&#x2F;code&gt;，通常作为函数的第一个参数。这使得上下文的传递透明且易于追踪，尤其是在跨 &lt;code&gt;API&lt;&#x2F;code&gt; 边界或服务层时。不要将上下文存储在结构体字段或全局变量中，这样做可能导致陈旧的上下文被无意间复用，使取消逻辑更难理解和处理。&lt;&#x2F;li&gt;
&lt;li&gt;上下文只应用于请求范围内的元数据，不要用来传递业务逻辑或应用状态。滥用上下文进行通用数据存储会导致紧耦合，增加测试和追踪的难度。&lt;&#x2F;li&gt;
&lt;li&gt;在需要时检查 &lt;code&gt;ctx.Err()&lt;&#x2F;code&gt;，以区分 &lt;code&gt;context.Canceled&lt;&#x2F;code&gt; 和 &lt;code&gt;context.DeadlineExceeded&lt;&#x2F;code&gt;。这样可以让应用程序做出适当响应，例如区分用户主动取消和超时情况。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;遵循这些实践，有助于保持上下文使用的可预测性和惯用性。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;goperf.dev&#x2F;01-common-patterns&#x2F;context&#x2F;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | 利用 Go 的编译器优化标志</title>
          <pubDate>Thu, 17 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-17-leveraging-compiler-optimization-flags-in-go/</link>
          <guid>https://inasa.dev/posts/25-04-17-leveraging-compiler-optimization-flags-in-go/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-17-leveraging-compiler-optimization-flags-in-go/">&lt;p&gt;在优化 &lt;code&gt;Go&lt;&#x2F;code&gt; 应用程序的性能时，通常关注性能分析、内存分配或并发模式。但另一个值得考虑的层面是 &lt;code&gt;Go&lt;&#x2F;code&gt; 编译器在构建过程中如何优化代码。&lt;&#x2F;p&gt;
&lt;p&gt;虽然 &lt;code&gt;Go&lt;&#x2F;code&gt; 没有像 &lt;code&gt;C&lt;&#x2F;code&gt; 或 &lt;code&gt;Rust&lt;&#x2F;code&gt; 那样暴露出细粒度的编译器标志，但它仍然提供了有用的方法来影响你的代码构建，尤其是在针对性能、二进制大小或特定环境时。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wei-shen-me-bian-yi-qi-biao-zhi-hen-zhong-yao&quot;&gt;为什么编译器标志很重要&lt;a class=&quot;zola-anchor&quot; href=&quot;#wei-shen-me-bian-yi-qi-biao-zhi-hen-zhong-yao&quot; aria-label=&quot;Anchor link for: wei-shen-me-bian-yi-qi-biao-zhi-hen-zhong-yao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Go 的编译器（具体来说是 &lt;code&gt;cmd&#x2F;compile&lt;&#x2F;code&gt; 和 &lt;code&gt;cmd&#x2F;link&lt;&#x2F;code&gt;）执行几种默认优化：内联、逃逸分析、死代码消除等。然而，在某些情况下，通过使用正确的标志，可以挤出更多的性能或控制构建。&lt;&#x2F;p&gt;
&lt;p&gt;使用场景包括：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;降低最小容器或嵌入式系统的二进制文件大小&lt;&#x2F;li&gt;
&lt;li&gt;针对特定架构或操作系统构建&lt;&#x2F;li&gt;
&lt;li&gt;在发布构建中去除调试信息&lt;&#x2F;li&gt;
&lt;li&gt;暂时禁用优化以便于调试&lt;&#x2F;li&gt;
&lt;li&gt;开启实验性或不安全的性能技巧（谨慎使用）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;guan-jian-bian-yi-qi-he-lian-jie-qi-biao-zhi&quot;&gt;关键编译器和链接器标志&lt;a class=&quot;zola-anchor&quot; href=&quot;#guan-jian-bian-yi-qi-he-lian-jie-qi-biao-zhi&quot; aria-label=&quot;Anchor link for: guan-jian-bian-yi-qi-he-lian-jie-qi-biao-zhi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;ldflags-s-w-shan-chu-diao-shi-xin-xi&quot;&gt;&lt;code&gt;-ldflags=&quot;-s -w&quot;&lt;&#x2F;code&gt; 删除调试信息&lt;a class=&quot;zola-anchor&quot; href=&quot;#ldflags-s-w-shan-chu-diao-shi-xin-xi&quot; aria-label=&quot;Anchor link for: ldflags-s-w-shan-chu-diao-shi-xin-xi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;当你想要减小二进制文件大小时，特别是在生产环境或容器中：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;go&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;ldflags&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;-s -w&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; app main.go&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-s&lt;&#x2F;code&gt;: 去除符号表&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-w&lt;&#x2F;code&gt;: 去除 &lt;code&gt;DWARF&lt;&#x2F;code&gt; 调试信息&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;为什么重要：这可以将二进制文件大小减少 30-40%，具体取决于代码库。这在 &lt;code&gt;Docker&lt;&#x2F;code&gt; 镜像中或分发二进制文件时非常有用。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gcflags-kong-zhi-bian-yi-qi-you-hua&quot;&gt;&lt;code&gt;-gcflags&lt;&#x2F;code&gt; 控制编译器优化&lt;a class=&quot;zola-anchor&quot; href=&quot;#gcflags-kong-zhi-bian-yi-qi-you-hua&quot; aria-label=&quot;Anchor link for: gcflags-kong-zhi-bian-yi-qi-you-hua&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;-gcflags&lt;&#x2F;code&gt; 标志允许你控制编译器如何处理特定包。例如，可以禁用调试时的优化：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;go&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;gcflags&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;all=-N -l&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; app main.go&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-N&lt;&#x2F;code&gt;: 禁用优化&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-l&lt;&#x2F;code&gt;: 禁用内联&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;何时使用：在使用 &lt;code&gt;Delve&lt;&#x2F;code&gt; 或类似工具进行调试时。禁用内联和优化使得堆栈跟踪和断点更加可靠。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;jiao-cha-bian-yi-biao-zhi&quot;&gt;交叉编译标志&lt;a class=&quot;zola-anchor&quot; href=&quot;#jiao-cha-bian-yi-biao-zhi&quot; aria-label=&quot;Anchor link for: jiao-cha-bian-yi-biao-zhi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;GOOS&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;linux&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;GOARCH&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;arm64&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;go&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; app main.go&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GOOS&lt;&#x2F;code&gt;, &lt;code&gt;GOARCH&lt;&#x2F;code&gt;: 设置目标操作系统和架构&lt;&#x2F;li&gt;
&lt;li&gt;常见值：&lt;code&gt;windows&lt;&#x2F;code&gt;, &lt;code&gt;darwin&lt;&#x2F;code&gt;, &lt;code&gt;linux&lt;&#x2F;code&gt;, &lt;code&gt;amd64&lt;&#x2F;code&gt;, &lt;code&gt;arm64&lt;&#x2F;code&gt;, &lt;code&gt;386&lt;&#x2F;code&gt;, &lt;code&gt;wasm&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;gou-jian-biao-qian&quot;&gt;构建标签&lt;a class=&quot;zola-anchor&quot; href=&quot;#gou-jian-biao-qian&quot; aria-label=&quot;Anchor link for: gou-jian-biao-qian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;构建标签允许条件编译。使用 &lt;code&gt;&#x2F;&#x2F;go:build&lt;&#x2F;code&gt; 或 &#x2F;&#x2F; &lt;code&gt;+build&lt;&#x2F;code&gt; 在你的源代码中控制编译内容。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-keyword z-annotation z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-punctuation z-accessor z-colon z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-variable z-function z-go&quot;&gt;build&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;debug&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;log&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;debugLog&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;msg&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;log&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;[DEBUG]&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;msg&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;go&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;tags&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;debug&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; app main.go&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;ldflags-x-zhu-ru-gou-jian-shi-bian-liang&quot;&gt;&lt;code&gt;-ldflags=&quot;-X ...&quot;&lt;&#x2F;code&gt; 注入构建时变量&lt;a class=&quot;zola-anchor&quot; href=&quot;#ldflags-x-zhu-ru-gou-jian-shi-bian-liang&quot; aria-label=&quot;Anchor link for: ldflags-x-zhu-ru-gou-jian-shi-bian-liang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;可以在构建时将版本号或元数据注入到二进制文件中：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; main.go
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;fmt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;version&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;dev&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;App version: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%s&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;version&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;go&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;ldflags&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;-s -w -X main.version=1.0.0&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; app main.go&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这会在链接时设置 &lt;code&gt;version&lt;&#x2F;code&gt; 变量，而不会修改源代码。它对于嵌入发布版本、提交哈希或构建日期非常有用。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;extldflags-static-gou-jian-wan-quan-jing-tai-de-er-jin-zhi-wen-jian&quot;&gt;&lt;code&gt;-extldflags=&#x27;-static&#x27;&lt;&#x2F;code&gt; 构建完全静态的二进制文件&lt;a class=&quot;zola-anchor&quot; href=&quot;#extldflags-static-gou-jian-wan-quan-jing-tai-de-er-jin-zhi-wen-jian&quot; aria-label=&quot;Anchor link for: extldflags-static-gou-jian-wan-quan-jing-tai-de-er-jin-zhi-wen-jian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;-extldflags &#x27;-static&#x27;&lt;&#x2F;code&gt; 选项传递 &lt;code&gt;-static&lt;&#x2F;code&gt; 标志给外部系统链接器，指示其生成一个完全静态链接的二进制文件。&lt;&#x2F;p&gt;
&lt;p&gt;这在使用 &lt;code&gt;CGO&lt;&#x2F;code&gt; 并希望避免动态库依赖时尤其有用：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;CGO_ENABLED&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;1&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;GOOS&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;linux&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;GOARCH&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;amd64&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;CC&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;gcc&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;go&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;ldflags&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;-linkmode=external -extldflags=&amp;#39;-static&amp;#39;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; app main.go&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;它的作用：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;将所有 &lt;code&gt;C&lt;&#x2F;code&gt; 库静态链接到二进制文件中&lt;&#x2F;li&gt;
&lt;li&gt;生成一个便携、自包含的可执行文件&lt;&#x2F;li&gt;
&lt;li&gt;适用于最小化的容器（如 &lt;code&gt;scratch&lt;&#x2F;code&gt; 或 &lt;code&gt;distroless&lt;&#x2F;code&gt;）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;为了进一步确保二进制文件避免依赖 &lt;code&gt;C&lt;&#x2F;code&gt; 库的 &lt;code&gt;DNS&lt;&#x2F;code&gt; 解析（例如 &lt;code&gt;glibc&lt;&#x2F;code&gt; 的 &lt;code&gt;getaddrinfo&lt;&#x2F;code&gt;），你可以使用 &lt;code&gt;netgo&lt;&#x2F;code&gt; 构建标签。这强制 &lt;code&gt;Go&lt;&#x2F;code&gt; 使用其纯 &lt;code&gt;Go&lt;&#x2F;code&gt; 实现的 &lt;code&gt;DNS&lt;&#x2F;code&gt; 解析器：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;CGO_ENABLED&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;1&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;GOOS&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;linux&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;GOARCH&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;amd64&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;CC&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;gcc&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;go&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;tags&lt;&#x2F;span&gt; netgo&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;ldflags&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;-linkmode=external -extldflags=&amp;#39;-static&amp;#39;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; app main.go&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在为最小化的容器环境构建时，这一步尤其重要，因为动态 &lt;code&gt;libc&lt;&#x2F;code&gt; 依赖可能不可用。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;静态链接要求使用库的静态版本（&lt;code&gt;.a&lt;&#x2F;code&gt;），可能无法与所有 &lt;code&gt;C&lt;&#x2F;code&gt; 库一起使用。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;shi-li-tong-guo-cgo-shi-yong-libcurl-jin-xing-jing-tai-gou-jian&quot;&gt;示例：通过 &lt;code&gt;CGO&lt;&#x2F;code&gt; 使用 &lt;code&gt;libcurl&lt;&#x2F;code&gt; 进行静态构建&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-li-tong-guo-cgo-shi-yong-libcurl-jin-xing-jing-tai-gou-jian&quot; aria-label=&quot;Anchor link for: shi-li-tong-guo-cgo-shi-yong-libcurl-jin-xing-jing-tai-gou-jian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;如果使用 &lt;code&gt;libcurl&lt;&#x2F;code&gt; 与 &lt;code&gt;CGO&lt;&#x2F;code&gt;，这里是如何创建一个静态链接的 &lt;code&gt;Go&lt;&#x2F;code&gt; 二进制文件：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-go&quot;&gt;&#x2F;*&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-block z-go&quot;&gt;#cgo LDFLAGS: -lcurl
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-block z-go&quot;&gt;#include &amp;lt;curl&#x2F;curl.h&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-end z-go&quot;&gt;*&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;C&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;fmt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;libcurl version:&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;C&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;GoString&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;C&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;curl_version&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;#cgo LDFLAGS: -lcurl&lt;&#x2F;code&gt;: 告诉 &lt;code&gt;Go&lt;&#x2F;code&gt; 编译器在链接时使用 &lt;code&gt;libcurl&lt;&#x2F;code&gt; 库。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;#include &amp;lt;curl&#x2F;curl.h&amp;gt;&lt;&#x2F;code&gt;: &lt;code&gt;C&lt;&#x2F;code&gt; 语言的预处理指令，用于包含 &lt;code&gt;libcurl&lt;&#x2F;code&gt; 的头文件。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;静态构建命令：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;CGO_ENABLED&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;1&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;GOOS&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;linux&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;GOARCH&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;amd64&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;CC&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;gcc&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-continuation z-line z-shell&quot;&gt;\
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;go&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; build&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;tags&lt;&#x2F;span&gt; netgo&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;ldflags&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;-linkmode=external -extldflags=&amp;#39;-static&amp;#39;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;o&lt;&#x2F;span&gt; app main.go&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;确保你的系统上可用静态版本的 &lt;code&gt;libcurl (libcurl.a)&lt;&#x2F;code&gt;。你可能需要安装开发包或从源代码构建 &lt;code&gt;libcurl&lt;&#x2F;code&gt;，使用 &lt;code&gt;--enable-static&lt;&#x2F;code&gt; 选项。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;goperf.dev&#x2F;01-common-patterns&#x2F;comp-flags&#x2F;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Linux | rsyslog收集网络日志示例</title>
          <pubDate>Wed, 16 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-16-rsyslog-remote-log/</link>
          <guid>https://inasa.dev/posts/25-04-16-rsyslog-remote-log/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-16-rsyslog-remote-log/">&lt;h2 id=&quot;fu-wu-duan&quot;&gt;服务端&lt;a class=&quot;zola-anchor&quot; href=&quot;#fu-wu-duan&quot; aria-label=&quot;Anchor link for: fu-wu-duan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;安装&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;apt-get&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; install rsyslog&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;配置 &lt;code&gt;rsyslog&lt;&#x2F;code&gt; 接收网络日志&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;vim&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;etc&#x2F;rsyslog.conf&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;找到以下行，并取消注释或添加&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;module&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;(load=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;imudp&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;input&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;(type=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;imudp&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; port=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;514&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;module&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;(load=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;imtcp&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;input&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;(type=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;imtcp&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; port=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;514&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;配置日志文件存储规则,指定如何处理接收到的日志,添加以下行到 &lt;code&gt;&#x2F;etc&#x2F;rsyslog.conf&lt;&#x2F;code&gt; 末尾。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; 提供一个模板以指定日志存储的格式和位置&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;template&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;(name=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;RemoteLog&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; type=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;string&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; string=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;var&#x2F;log&#x2F;%HOSTNAME%&#x2F;%PROGRAMNAME%.log&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;或者使用ip&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;template&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;(name=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;RemoteLog&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; type=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;string&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; string=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&#x2F;var&#x2F;log&#x2F;%fromhost-ip%&#x2F;%PROGRAMNAME%.log&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; 使用模板处理所有远程日志&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-keyword z-control z-conditional z-if z-shell&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;fromhost&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;-ip&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; != &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;127.0.0.1&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; then -&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;?&lt;&#x2F;span&gt;RemoteLog&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-job z-shell&quot;&gt;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;stop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;重启 &lt;code&gt;rsyslog&lt;&#x2F;code&gt; 服务&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; restart rsyslog&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;测试,在其他机器上执行命令&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;logger&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;n&lt;&#x2F;span&gt; your-syslog-server-ip&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;P&lt;&#x2F;span&gt; 514&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;T&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Test message&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;ke-hu-duan&quot;&gt;客户端&lt;a class=&quot;zola-anchor&quot; href=&quot;#ke-hu-duan&quot; aria-label=&quot;Anchor link for: ke-hu-duan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;修改 &lt;code&gt;rsyslog&lt;&#x2F;code&gt; 配置以转发日志&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;vim&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;etc&#x2F;rsyslog.conf&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;配置转发规则,确保以下模块加载行是启用的&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;module&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;(load=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;imuxsock&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)  &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; provides support for local system logging&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;module&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;(load=&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;imklog&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)    &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; provides kernel logging support&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;添加转发规则来指定远程 Syslog 服务器的地址&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; 将 &#x2F;var&#x2F;log 下的所有日志级别和设施的消息转发到指定的远程 Syslog 服务器&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;*.*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; @@remote-syslog-server-ip:514&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-logical z-continue z-shell&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;RSYSLOG_SyslogProtocol23Format&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;*.*&lt;&#x2F;code&gt; 表示所有的日志级别和设施
&lt;ul&gt;
&lt;li&gt;第一个星号代表所有的日志设施（如 &lt;code&gt;auth&lt;&#x2F;code&gt;, &lt;code&gt;cron&lt;&#x2F;code&gt;, &lt;code&gt;daemon&lt;&#x2F;code&gt;, &lt;code&gt;kern&lt;&#x2F;code&gt;, &lt;code&gt;mail&lt;&#x2F;code&gt; 等）&lt;&#x2F;li&gt;
&lt;li&gt;第二个星号代表所有的优先级（如 &lt;code&gt;emerg&lt;&#x2F;code&gt;, &lt;code&gt;alert&lt;&#x2F;code&gt;, &lt;code&gt;crit&lt;&#x2F;code&gt;, &lt;code&gt;err&lt;&#x2F;code&gt;, &lt;code&gt;warning&lt;&#x2F;code&gt;, &lt;code&gt;notice&lt;&#x2F;code&gt;, &lt;code&gt;info&lt;&#x2F;code&gt;, &lt;code&gt;debug&lt;&#x2F;code&gt;）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;@@&lt;&#x2F;code&gt; 表示使用 &lt;code&gt;TCP&lt;&#x2F;code&gt; 协议发送（如果只想用 &lt;code&gt;UDP&lt;&#x2F;code&gt;，使用单个 &lt;code&gt;@&lt;&#x2F;code&gt;）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;remote-syslog-server-ip&lt;&#x2F;code&gt; 是你的 &lt;code&gt;Syslog&lt;&#x2F;code&gt; 服务器的 &lt;code&gt;IP&lt;&#x2F;code&gt; 地址&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;514&lt;&#x2F;code&gt; 是 &lt;code&gt;Syslog&lt;&#x2F;code&gt; 服务监听的端口&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;RSYSLOG_SyslogProtocol23Format&lt;&#x2F;code&gt; 是使用的日志格式&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;所有这些规则都应该被添加到 &lt;code&gt;&#x2F;etc&#x2F;rsyslog.conf&lt;&#x2F;code&gt; 或分散在 &lt;code&gt;&#x2F;etc&#x2F;rsyslog.d&#x2F;&lt;&#x2F;code&gt; 目录下的文件中。&lt;&#x2F;p&gt;
&lt;p&gt;重启 &lt;code&gt;rsyslog&lt;&#x2F;code&gt; 服务&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; restart rsyslog&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;测试,在客户端上测试&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;logger&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;This is a test message from the client machine&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</description>
      </item>
      <item>
          <title>Windows | heredoc示例</title>
          <pubDate>Wed, 16 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-16-windows-heredoc/</link>
          <guid>https://inasa.dev/posts/25-04-16-windows-heredoc/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-16-windows-heredoc/">&lt;p&gt;以&lt;code&gt;nginx&lt;&#x2F;code&gt;配置文件为例&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;powershell&quot; class=&quot;language-powershell z-code&quot;&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-powershell&quot;&gt;$&lt;&#x2F;span&gt;config&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;@&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;worker_processes  1;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;events {
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;    worker_connections  1024;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;http {
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;    include       mime.types;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;    default_type  application&#x2F;octet-stream;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;    log_format  main  &amp;#39;$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; &amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;                     &amp;#39;$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; &amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;                     &amp;#39;&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot;&amp;#39;;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;    access_log  &#x2F;var&#x2F;log&#x2F;nginx&#x2F;access.log  main;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;    error_log  &#x2F;var&#x2F;log&#x2F;nginx&#x2F;error.log;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;    sendfile        on;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;    keepalive_timeout  65;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;    client_max_body_size 0;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;    server_tokens off;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;    gzip  on;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;    server {
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;        listen 80 reuseport;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;        location &#x2F; {
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;            root   &#x2F;www;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;            index  index.html;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;        }
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;    }
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-heredoc z-powershell&quot;&gt;&amp;#39;@&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-powershell&quot;&gt;$&lt;&#x2F;span&gt;config&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-other z-powershell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-powershell&quot;&gt;Set-Content&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;Path &lt;span class=&quot;z-string z-quoted z-double z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;C:\Users\root\Desktop\nginx\conf\nginx.conf&lt;span class=&quot;z-punctuation z-definition z-string z-end z-powershell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;Encoding ASCII 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</description>
      </item>
      <item>
          <title>Go | 使用PGO优化编译示例</title>
          <pubDate>Tue, 15 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-15-golang-pgo-example/</link>
          <guid>https://inasa.dev/posts/25-04-15-golang-pgo-example/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-15-golang-pgo-example/">&lt;p&gt;PGO (Profile-Guided Optimization) 是一种编译优化技术，通过收集程序的实际运行时数据来指导编译器进行更有针对性的优化。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; class=&quot;language-txt z-code&quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-pgo file
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        specify the file path of a profile for profile-guided optimization (PGO).
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        When the special name &amp;quot;auto&amp;quot; is specified, for each main package in the
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        build, the go command selects a file named &amp;quot;default.pgo&amp;quot; in the package&amp;#39;s
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        directory if that file exists, and applies it to the (transitive)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        dependencies of the main package (other packages are not affected).
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        Special name &amp;quot;off&amp;quot; turns off PGO. The default is &amp;quot;auto&amp;quot;.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这段说明解释了 &lt;code&gt;-pgo&lt;&#x2F;code&gt; 参数的几种用法：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;pgo=文件路径&lt;&#x2F;code&gt; - 指定一个具体的性能分析文件路径用于PGO优化&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;pgo=auto&lt;&#x2F;code&gt; - 自动模式(默认)，会在每个main包的目录中查找名为&quot;default.pgo&quot;的文件&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;pgo=off&lt;&#x2F;code&gt; - 明确关闭PGO优化&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;当使用自动模式时，PGO优化只会应用到main包及其依赖项，而不会影响其他不相关的包。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;shou-ji-xing-neng-fen-xi-shu-ju&quot;&gt;收集性能分析数据&lt;a class=&quot;zola-anchor&quot; href=&quot;#shou-ji-xing-neng-fen-xi-shu-ju&quot; aria-label=&quot;Anchor link for: shou-ji-xing-neng-fen-xi-shu-ju&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; main.go
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;    &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;os&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;    &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;runtime&#x2F;pprof&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;computeIntensive&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;10000000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;++&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;+=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;%&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;10&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;result&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 第一次运行时开启性能分析
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Args&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;profile&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;os&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Create&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;profile.pprof&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;defer&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Close&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;pprof&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;StartCPUProfile&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;defer&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;pprof&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;StopCPUProfile&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 执行计算密集型操作
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;result&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;computeIntensive&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;println&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Result:&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;result&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;powershell&quot; class=&quot;language-powershell z-code&quot;&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;go build &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;o &lt;span class=&quot;z-support z-function z-powershell&quot;&gt;myapp.exe&lt;&#x2F;span&gt; .
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;.&lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-powershell&quot;&gt;myapp.exe&lt;&#x2F;span&gt; profile
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;shi-yong-shou-ji-de-fen-xi-shu-ju-jin-xing-you-hua-bian-yi&quot;&gt;使用收集的分析数据进行优化编译&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-yong-shou-ji-de-fen-xi-shu-ju-jin-xing-you-hua-bian-yi&quot; aria-label=&quot;Anchor link for: shi-yong-shou-ji-de-fen-xi-shu-ju-jin-xing-you-hua-bian-yi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;powershell&quot; class=&quot;language-powershell z-code&quot;&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;go build &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;pgo profile.pprof &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;o &lt;span class=&quot;z-support z-function z-powershell&quot;&gt;myapp_optimized.exe&lt;&#x2F;span&gt; .
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;如果有多个pprof文件&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;powershell&quot; class=&quot;language-powershell z-code&quot;&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-comment z-line z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-powershell&quot;&gt;#&lt;&#x2F;span&gt; 使用pprof工具合并多个分析文件&lt;span class=&quot;z-punctuation z-definition z-comment z-powershell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;go tool pprof &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;proto cpu1.pprof cpu2.pprof cpu3.pprof &lt;span class=&quot;z-keyword z-operator z-redirection z-powershell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; combined.pprof
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;&lt;span class=&quot;z-comment z-line z-powershell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-powershell&quot;&gt;#&lt;&#x2F;span&gt; 使用合并后的分析文件进行构建&lt;span class=&quot;z-punctuation z-definition z-comment z-powershell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;go build &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;pgo combined.pprof &lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;-&lt;&#x2F;span&gt;o &lt;span class=&quot;z-support z-function z-powershell&quot;&gt;myapp_optimized.exe&lt;&#x2F;span&gt; .
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;ce-shi&quot;&gt;测试&lt;a class=&quot;zola-anchor&quot; href=&quot;#ce-shi&quot; aria-label=&quot;Anchor link for: ce-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;powershell&quot; class=&quot;language-powershell z-code&quot;&gt;&lt;code class=&quot;language-powershell&quot; data-lang=&quot;powershell&quot;&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;time .&lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-powershell&quot;&gt;myapp.exe&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-powershell&quot;&gt;time .&lt;span class=&quot;z-keyword z-operator z-assignment z-powershell&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-powershell&quot;&gt;myapp_optimized.exe&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;PGO 优化通常在较大、复杂的应用中效果更显著，特别是有明显热点路径的程序。对于简单程序，优化效果可能不明显，甚至因为优化开销而略微变慢。&lt;&#x2F;li&gt;
&lt;li&gt;PGO 主要适用于计算密集型应用。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Rust | LTO和Thin LTO编译器</title>
          <pubDate>Tue, 15 Apr 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/25-04-15-lto-thin-lto/</link>
          <guid>https://inasa.dev/posts/25-04-15-lto-thin-lto/</guid>
          <description xml:base="https://inasa.dev/posts/25-04-15-lto-thin-lto/">&lt;h2 id=&quot;lto-link-time-optimization&quot;&gt;LTO (Link Time Optimization)&lt;a class=&quot;zola-anchor&quot; href=&quot;#lto-link-time-optimization&quot; aria-label=&quot;Anchor link for: lto-link-time-optimization&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;链接时优化是一种编译器优化技术，它在程序的链接阶段而非传统的编译阶段执行代码优化。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;lto-de-gong-zuo-yuan-li&quot;&gt;LTO 的工作原理&lt;a class=&quot;zola-anchor&quot; href=&quot;#lto-de-gong-zuo-yuan-li&quot; aria-label=&quot;Anchor link for: lto-de-gong-zuo-yuan-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;编译阶段&lt;&#x2F;strong&gt;：编译器在编译单个源文件时，不仅生成机器代码，还保存中间表示（IR，Intermediate Representation）到目标文件中&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;链接阶段&lt;&#x2F;strong&gt;：链接器收集所有模块的IR，将它们合并为一个统一的程序表示&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;全局优化&lt;&#x2F;strong&gt;：对整个程序执行优化，基于对所有代码的完整视图&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;lto-de-zhu-yao-you-shi&quot;&gt;LTO 的主要优势&lt;a class=&quot;zola-anchor&quot; href=&quot;#lto-de-zhu-yao-you-shi&quot; aria-label=&quot;Anchor link for: lto-de-zhu-yao-you-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;跨模块优化&lt;&#x2F;strong&gt;：可以进行跨越多个源文件的优化&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;内联函数&lt;&#x2F;strong&gt;：更强大的函数内联能力，包括跨编译单元边界&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;死代码消除&lt;&#x2F;strong&gt;：更有效地移除未使用的代码&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;更精确的别名分析&lt;&#x2F;strong&gt;：改进指针分析和内存访问优化&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;代码大小减少&lt;&#x2F;strong&gt;：通过移除不必要的代码减小二进制大小&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;lto-de-que-dian&quot;&gt;LTO 的缺点&lt;a class=&quot;zola-anchor&quot; href=&quot;#lto-de-que-dian&quot; aria-label=&quot;Anchor link for: lto-de-que-dian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内存消耗大&lt;&#x2F;strong&gt;：处理大型程序时需要大量内存&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;编译时间长&lt;&#x2F;strong&gt;：链接过程变得更加复杂和耗时&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;thin-lto-qing-liang-ji-lian-jie-shi-you-hua&quot;&gt;Thin LTO (轻量级链接时优化)&lt;a class=&quot;zola-anchor&quot; href=&quot;#thin-lto-qing-liang-ji-lian-jie-shi-you-hua&quot; aria-label=&quot;Anchor link for: thin-lto-qing-liang-ji-lian-jie-shi-you-hua&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Thin LTO 是 LLVM 编译器基础设施引入的 LTO 变种，旨在解决传统 LTO 的性能和扩展性问题。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thin-lto-de-gong-zuo-yuan-li&quot;&gt;Thin LTO 的工作原理&lt;a class=&quot;zola-anchor&quot; href=&quot;#thin-lto-de-gong-zuo-yuan-li&quot; aria-label=&quot;Anchor link for: thin-lto-de-gong-zuo-yuan-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;索引生成&lt;&#x2F;strong&gt;：每个目标文件都独立生成索引，包含符号和引用信息&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;并行优化&lt;&#x2F;strong&gt;：基于索引信息，将全局优化工作分解成多个可并行执行的任务&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;模块级优化&lt;&#x2F;strong&gt;：在各个模块上并行执行优化，而不是合并所有IR&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;thin-lto-de-zhu-yao-you-shi&quot;&gt;Thin LTO 的主要优势&lt;a class=&quot;zola-anchor&quot; href=&quot;#thin-lto-de-zhu-yao-you-shi&quot; aria-label=&quot;Anchor link for: thin-lto-de-zhu-yao-you-shi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;减少内存使用&lt;&#x2F;strong&gt;：不需要加载整个程序的IR到内存&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;并行编译&lt;&#x2F;strong&gt;：通过并行化加速编译过程&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;增量编译支持&lt;&#x2F;strong&gt;：更好地支持增量构建&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;保留大部分传统LTO的优化效果&lt;&#x2F;strong&gt;：仍能执行跨模块优化&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;特性&lt;&#x2F;th&gt;&lt;th&gt;LTO&lt;&#x2F;th&gt;&lt;th&gt;Thin LTO&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;优化效果&lt;&#x2F;td&gt;&lt;td&gt;最大化&lt;&#x2F;td&gt;&lt;td&gt;接近LTO但略低&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;内存使用&lt;&#x2F;td&gt;&lt;td&gt;高&lt;&#x2F;td&gt;&lt;td&gt;中等&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;编译速度&lt;&#x2F;td&gt;&lt;td&gt;慢&lt;&#x2F;td&gt;&lt;td&gt;快（尤其在多核系统）&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;并行度&lt;&#x2F;td&gt;&lt;td&gt;有限&lt;&#x2F;td&gt;&lt;td&gt;高&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;适用场景&lt;&#x2F;td&gt;&lt;td&gt;最终发布构建&lt;&#x2F;td&gt;&lt;td&gt;日常开发和发布&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;h2 id=&quot;rust-zhong-shi-yong&quot;&gt;Rust 中使用&lt;a class=&quot;zola-anchor&quot; href=&quot;#rust-zhong-shi-yong&quot; aria-label=&quot;Anchor link for: rust-zhong-shi-yong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;toml&quot; class=&quot;language-toml z-code&quot;&gt;&lt;code class=&quot;language-toml&quot; data-lang=&quot;toml&quot;&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-table z-begin z-toml&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-tag z-table z-toml&quot;&gt;&lt;span class=&quot;z-entity z-name z-table z-toml&quot;&gt;profile&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-table z-toml&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-table z-toml&quot;&gt;release&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-table z-end z-toml&quot;&gt;]&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-toml&quot;&gt;#&lt;&#x2F;span&gt; lto = &amp;quot;off&amp;quot;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-toml&quot;&gt;#&lt;&#x2F;span&gt; lto = &amp;quot;fat&amp;quot;   &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-toml&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-toml&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-toml&quot;&gt;#&lt;&#x2F;span&gt; lto = &amp;quot;thin&amp;quot;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;LTO 通常与其他优化标志一起使用。&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Linux | 如何在终端使用Progress bar</title>
          <pubDate>Sat, 24 Aug 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-08-24-terminal-progressbar/</link>
          <guid>https://inasa.dev/posts/24-08-24-terminal-progressbar/</guid>
          <description xml:base="https://inasa.dev/posts/24-08-24-terminal-progressbar/">&lt;p&gt;原理：使用 ANSI 转义序列来控制光标位置&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;python&quot; class=&quot;language-python z-code&quot;&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-python&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;time&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-statement z-import z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-python&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;sys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function z-python&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-python&quot;&gt;&lt;span class=&quot;z-keyword z-declaration z-function z-python&quot;&gt;def&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;progress_bar&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-python&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-python&quot;&gt;total&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-function z-begin z-python&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;    &lt;span class=&quot;z-meta z-statement z-loop z-for z-python&quot;&gt;&lt;span class=&quot;z-keyword z-control z-loop z-for z-python&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-loop z-for z-in z-python&quot;&gt;in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-loop z-for z-python&quot;&gt; &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;range&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;total&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-python&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-statement z-loop z-for z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-loop z-for z-python&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;        &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;percent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;&#x2F;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;total&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-python&quot;&gt;100&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;        &lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt; bar = &amp;#39;█&amp;#39; * (i &#x2F;&#x2F; 2) + &amp;#39;-&amp;#39; * (total &#x2F;&#x2F; 2 - i &#x2F;&#x2F; 2)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;        &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;bar&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-python&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-constant z-character z-escape z-unicode z-32-bit-hex z-python&quot;&gt;\u2588&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;&#x2F;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-python&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;+&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;-&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;total&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;&#x2F;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-python&quot;&gt;2&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-arithmetic z-python&quot;&gt;&#x2F;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-python&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;sys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;stdout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;write&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-string z-python&quot;&gt;f&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-interpolated z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-string z-interpolated z-python&quot;&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;&lt;span class=&quot;z-constant z-character z-escape z-python&quot;&gt;\r&lt;&#x2F;span&gt;Progress: |&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-interpolation z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-interpolation z-begin z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python z-embedded&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;bar&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-interpolation z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-interpolation z-end z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;| &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-interpolation z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-interpolation z-begin z-python&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python z-embedded&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;percent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-format-spec z-python&quot;&gt;&lt;span class=&quot;z-constant z-other z-format-spec z-python&quot;&gt;:.2f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-interpolation z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-interpolation z-end z-python&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-python&quot;&gt;%&lt;span class=&quot;z-punctuation z-definition z-string z-end z-python&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;sys&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;stdout&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;flush&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;        &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;time&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-python&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;sleep&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-float z-decimal z-python&quot;&gt;0&lt;span class=&quot;z-punctuation z-separator z-decimal z-python&quot;&gt;.&lt;&#x2F;span&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;  &lt;span class=&quot;z-comment z-line z-number-sign z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-python&quot;&gt;#&lt;&#x2F;span&gt; 模拟工作
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;    &lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-python&quot;&gt;print&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-python&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-python&quot;&gt;&lt;span class=&quot;z-meta z-qualified-name z-python&quot;&gt;&lt;span class=&quot;z-variable z-function z-python&quot;&gt;&lt;span class=&quot;z-meta z-generic-name z-python&quot;&gt;progress_bar&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-python&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-begin z-python&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-python&quot;&gt;100&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-arguments z-end z-python&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;\r&lt;&#x2F;code&gt;：这个字符的作用是将光标移动到当前行的开头，而不是换到下一行。这样可以覆盖当前行的内容，实现动态更新。&lt;strong&gt;必须写在字符串的最前面，以确保光标移动到当前行的开头。&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;使用 &lt;code&gt;i &#x2F;&#x2F; 2&lt;&#x2F;code&gt; 的原因是为了将进度条的长度控制在一个合适的范围内,减少进度条的字符数量，易于阅读&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Invest | 3.PDT规则（Pattern Day Trader Rule）</title>
          <pubDate>Fri, 23 Aug 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-08-23-invest-pdt/</link>
          <guid>https://inasa.dev/posts/24-08-23-invest-pdt/</guid>
          <description xml:base="https://inasa.dev/posts/24-08-23-invest-pdt/">&lt;p&gt;PDT规则（Pattern Day Trader Rule）是美国金融业监管局（FINRA）设立的一项规定，旨在限制和管理高频日内交易行为。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pdtgui-ze-de-ding-yi-he-yao-qiu&quot;&gt;PDT规则的定义和要求&lt;a class=&quot;zola-anchor&quot; href=&quot;#pdtgui-ze-de-ding-yi-he-yao-qiu&quot; aria-label=&quot;Anchor link for: pdtgui-ze-de-ding-yi-he-yao-qiu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;ding-yi&quot;&gt;定义&lt;a class=&quot;zola-anchor&quot; href=&quot;#ding-yi&quot; aria-label=&quot;Anchor link for: ding-yi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;如果在连续的五个交易日内，你进行了四次或更多次的日内交易（即在同一交易日内买入和卖出同一只股票），并且这些交易次数占你账户总交易次数的6%以上，你将被标记为“日内交易者”（Pattern Day Trader，PDT）。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zui-di-zhang-hu-yu-e-yao-qiu&quot;&gt;最低账户余额要求&lt;a class=&quot;zola-anchor&quot; href=&quot;#zui-di-zhang-hu-yu-e-yao-qiu&quot; aria-label=&quot;Anchor link for: zui-di-zhang-hu-yu-e-yao-qiu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;被标记为PDT的账户必须维持至少25,000美元的最低账户余额。如果账户余额低于25,000美元，券商将限制该账户进行进一步的日内交易，直到账户余额恢复到规定的最低水平。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zhang-hu-lei-xing&quot;&gt;账户类型&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhang-hu-lei-xing&quot; aria-label=&quot;Anchor link for: zhang-hu-lei-xing&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;PDT规则适用于保证金账户（Margin Account），不适用于现金账户（Cash Account）。在现金账户中，资金结算周期（T+2）将限制频繁的买卖操作。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;pdtgui-ze-de-ying-xiang-he-zhu-yi-shi-xiang&quot;&gt;PDT规则的影响和注意事项&lt;a class=&quot;zola-anchor&quot; href=&quot;#pdtgui-ze-de-ying-xiang-he-zhu-yi-shi-xiang&quot; aria-label=&quot;Anchor link for: pdtgui-ze-de-ying-xiang-he-zhu-yi-shi-xiang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;jiao-yi-xian-zhi&quot;&gt;交易限制&lt;a class=&quot;zola-anchor&quot; href=&quot;#jiao-yi-xian-zhi&quot; aria-label=&quot;Anchor link for: jiao-yi-xian-zhi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;如果你被标记为PDT，并且账户余额低于25,000美元，券商可能会限制你进行日内交易，直到你存入足够的资金使账户余额达到或超过25,000美元。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;20240824 update:
貌似长桥香港没有这个限制，理论上可以无限日内交易。&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;feng-xian-guan-li&quot;&gt;风险管理&lt;a class=&quot;zola-anchor&quot; href=&quot;#feng-xian-guan-li&quot; aria-label=&quot;Anchor link for: feng-xian-guan-li&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;PDT规则旨在保护投资者免受高频交易带来的高风险和高波动性影响。高频日内交易需要高度的市场分析能力和快速反应能力，普通投资者应谨慎参与。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;jiao-yi-ce-lue&quot;&gt;交易策略&lt;a class=&quot;zola-anchor&quot; href=&quot;#jiao-yi-ce-lue&quot; aria-label=&quot;Anchor link for: jiao-yi-ce-lue&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;投资者应了解自己的交易行为是否符合PDT规则，并根据需要调整交易策略。例如，减少日内交易次数或保持账户余额在25,000美元以上。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;zong-jie&quot;&gt;总结&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;PDT规则是为了规范高频日内交易行为，保护投资者免受过度交易带来的风险。如果你在第一天做空，第二天买入股票，这种交易行为不属于日内交易，不会触发PDT规则的限制。但如果你进行频繁的日内交易，需确保了解并遵守PDT规则，避免账户受到限制。&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Centos | centos7升级openssh记录</title>
          <pubDate>Tue, 09 Jul 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-07-09-centos7-upgrade-openssh/</link>
          <guid>https://inasa.dev/posts/24-07-09-centos7-upgrade-openssh/</guid>
          <description xml:base="https://inasa.dev/posts/24-07-09-centos7-upgrade-openssh/">&lt;p&gt;升级OpenSSL到OpenSSL 1.1.1w&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;yum&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; install perl-core zlib-devel gcc&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;tar&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; xvf openssl-1.1.1w.tar.gz&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-cd z-shell&quot;&gt;cd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; openssl-1.1.1w&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;.&#x2F;config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;prefix&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;&#x2F;usr&#x2F;local&#x2F;openssl&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;openssldir&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;&#x2F;usr&#x2F;local&#x2F;openssl&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;j8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; install&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-echo z-shell&quot;&gt;echo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;export LD_LIBRARY_PATH=&#x2F;usr&#x2F;local&#x2F;openssl&#x2F;lib:$LD_LIBRARY_PATH&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt; &#x2F;etc&#x2F;profile&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-source z-shell&quot;&gt;source&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;etc&#x2F;profile&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;&#x2F;usr&#x2F;local&#x2F;openssl&#x2F;bin&#x2F;openssl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; version&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;升级Openssh到Openssh-9.8p1&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;tar&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; xvf openssh-9.8p1.tar.gz&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-support z-function z-cd z-shell&quot;&gt;cd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; openssh-9.8p1&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;.&#x2F;configure&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;prefix&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;&#x2F;usr&#x2F;local&#x2F;openssh&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;with-ssl-dir&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-option z-shell&quot;&gt;=&lt;&#x2F;span&gt;&#x2F;usr&#x2F;local&#x2F;openssl&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;j8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; install&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;usr&#x2F;sbin&#x2F;sshd &#x2F;usr&#x2F;sbin&#x2F;sshd.old&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &#x2F;usr&#x2F;bin&#x2F;ssh &#x2F;usr&#x2F;bin&#x2F;ssh.old&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;r&lt;&#x2F;span&gt; &#x2F;usr&#x2F;local&#x2F;openssh&#x2F;etc &#x2F;usr&#x2F;local&#x2F;openssh&#x2F;etc.bak&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-pipe z-shell&quot;&gt;|&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt; &#x2F;etc&#x2F;ssh&#x2F;ssh_host_&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;*&lt;&#x2F;span&gt; &#x2F;usr&#x2F;local&#x2F;openssh&#x2F;etc&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; sed&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;s&#x2F;#PermitRootLogin prohibit-password&#x2F;PermitRootLogin yes&#x2F;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &#x2F;usr&#x2F;local&#x2F;openssh&#x2F;etc&#x2F;sshd_config&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;lt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-control z-heredoc-token z-shell&quot;&gt;EOF&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-redirection z-shell&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &#x2F;usr&#x2F;lib&#x2F;systemd&#x2F;system&#x2F;sshd.service&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;[Unit]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;Description=OpenSSH server daemon
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;Documentation=man:sshd(8) man:sshd_config(5)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;After=network.target sshd-keygen.service
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;Wants=sshd-keygen.service
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;[Service]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;Type=notify
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;Environment=&amp;quot;LD_LIBRARY_PATH=&#x2F;usr&#x2F;local&#x2F;openssl&#x2F;lib:$LD_LIBRARY_PATH&amp;quot;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;EnvironmentFile=&#x2F;etc&#x2F;sysconfig&#x2F;sshd
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;ExecStart=&#x2F;usr&#x2F;sbin&#x2F;sshd -D $OPTIONS
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;ExecReload=&#x2F;bin&#x2F;kill -HUP $MAINPID
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;KillMode=process
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;Restart=on-failure
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;RestartSec=42s
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;[Install]
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;WantedBy=multi-user.target
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-string z-unquoted z-heredoc z-shell&quot;&gt;&lt;span class=&quot;z-keyword z-control z-heredoc-token z-shell&quot;&gt;EOF&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;rm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;f&lt;&#x2F;span&gt; &#x2F;usr&#x2F;sbin&#x2F;sshd &#x2F;usr&#x2F;bin&#x2F;ssh&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ln&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;s&lt;&#x2F;span&gt; &#x2F;usr&#x2F;local&#x2F;openssh&#x2F;sbin&#x2F;sshd &#x2F;usr&#x2F;sbin&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;ln&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;s&lt;&#x2F;span&gt; &#x2F;usr&#x2F;local&#x2F;openssh&#x2F;bin&#x2F;ssh &#x2F;usr&#x2F;bin&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; daemon-reload&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-and z-shell&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;systemctl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; restart sshd&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-logical z-and z-shell&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;sshd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; -&lt;&#x2F;span&gt;V&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</description>
      </item>
      <item>
          <title>Invest | 2.options期权</title>
          <pubDate>Wed, 29 May 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-05-29-invest-options/</link>
          <guid>https://inasa.dev/posts/24-05-29-invest-options/</guid>
          <description xml:base="https://inasa.dev/posts/24-05-29-invest-options/">&lt;h2 id=&quot;qi-quan-yu-gu-piao-de-qu-bie&quot;&gt;期权与股票的区别&lt;a class=&quot;zola-anchor&quot; href=&quot;#qi-quan-yu-gu-piao-de-qu-bie&quot; aria-label=&quot;Anchor link for: qi-quan-yu-gu-piao-de-qu-bie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;quan-li-yu-yi-wu&quot;&gt;权利与义务:&lt;a class=&quot;zola-anchor&quot; href=&quot;#quan-li-yu-yi-wu&quot; aria-label=&quot;Anchor link for: quan-li-yu-yi-wu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;股票买卖代表实际拥有或出售公司股份，持有者享有公司部分所有权。&lt;&#x2F;li&gt;
&lt;li&gt;期权买卖代表购买或出售某一特定价格执行的权利，而非直接的所有权。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;shi-jian-yin-su&quot;&gt;时间因素:&lt;a class=&quot;zola-anchor&quot; href=&quot;#shi-jian-yin-su&quot; aria-label=&quot;Anchor link for: shi-jian-yin-su&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;股票可以无限期持有，直到你决定卖出。&lt;&#x2F;li&gt;
&lt;li&gt;期权有到期日，持有者必须在到期日前决定是否行权。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;feng-xian-yu-shou-yi&quot;&gt;风险与收益:&lt;a class=&quot;zola-anchor&quot; href=&quot;#feng-xian-yu-shou-yi&quot; aria-label=&quot;Anchor link for: feng-xian-yu-shou-yi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;股票投资者的风险在于股票价格下跌，收益来自于股票价格上涨及可能的股息。&lt;&#x2F;li&gt;
&lt;li&gt;期权买方的风险限于所支付的溢价，但收益潜力较大；期权卖方的风险较高，但收入是固定的溢价。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;gang-gan-zuo-yong&quot;&gt;杠杆作用:&lt;a class=&quot;zola-anchor&quot; href=&quot;#gang-gan-zuo-yong&quot; aria-label=&quot;Anchor link for: gang-gan-zuo-yong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;期权通常具有杠杆作用，小额投资可以控制较大价值的标的资产。&lt;&#x2F;li&gt;
&lt;li&gt;股票交易一般没有内在杠杆，投资多少就得到相应价值的股票。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;qi-quan-ji-ben-cao-zuo&quot;&gt;期权基本操作&lt;a class=&quot;zola-anchor&quot; href=&quot;#qi-quan-ji-ben-cao-zuo&quot; aria-label=&quot;Anchor link for: qi-quan-ji-ben-cao-zuo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;期权合约: 期权是一种金融衍生工具，赋予持有人在未来某一日期以特定价格买入（看涨期权，Call）或卖出（看跌期权，Put）标的资产的权利。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;买入期权（购买权利）:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;看涨期权（Call）: 你支付一定的溢价，购买在未来某个日期以特定价格（行权价）买入标的资产的权利。如果标的资产价格上涨，你可以行使权利，以低于市场价的价格买入，从而获利。&lt;&#x2F;li&gt;
&lt;li&gt;看跌期权（Put）: 你支付一定的溢价，购买在未来某个日期以特定价格卖出标的资产的权利。如果标的资产价格下跌，你可以行使权利，以高于市场价的价格卖出，从而获利。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;卖出期权（出售权利）:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;你可以出售看涨或看跌期权，赚取溢价收入。但需要注意的是，卖出期权（尤其是未持有标的资产的裸卖）有较大的风险，因为你需要承担买方行权的义务。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;yi-xie-chang-yong-de-qi-quan-xiang-guan-shu-yu-ji-qi-ying-wen-fan-yi&quot;&gt;一些常用的期权相关术语及其英文翻译：&lt;a class=&quot;zola-anchor&quot; href=&quot;#yi-xie-chang-yong-de-qi-quan-xiang-guan-shu-yu-ji-qi-ying-wen-fan-yi&quot; aria-label=&quot;Anchor link for: yi-xie-chang-yong-de-qi-quan-xiang-guan-shu-yu-ji-qi-ying-wen-fan-yi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;期权合约: Option Contract&lt;&#x2F;li&gt;
&lt;li&gt;看涨期权: Call Option&lt;&#x2F;li&gt;
&lt;li&gt;看跌期权: Put Option&lt;&#x2F;li&gt;
&lt;li&gt;行权价: Strike Price&lt;&#x2F;li&gt;
&lt;li&gt;到期日: Expiration Date&lt;&#x2F;li&gt;
&lt;li&gt;溢价: Premium&lt;&#x2F;li&gt;
&lt;li&gt;行权: Exercise&lt;&#x2F;li&gt;
&lt;li&gt;平仓: Close the Position&lt;&#x2F;li&gt;
&lt;li&gt;未平仓合约: Open Interest&lt;&#x2F;li&gt;
&lt;li&gt;合约买方: Option Buyer (or Holder)&lt;&#x2F;li&gt;
&lt;li&gt;合约卖方: Option Seller (or Writer)&lt;&#x2F;li&gt;
&lt;li&gt;内在价值: Intrinsic Value&lt;&#x2F;li&gt;
&lt;li&gt;时间价值: Time Value&lt;&#x2F;li&gt;
&lt;li&gt;看涨期权买方: Call Option Buyer&lt;&#x2F;li&gt;
&lt;li&gt;看涨期权卖方: Call Option Seller&lt;&#x2F;li&gt;
&lt;li&gt;看跌期权买方: Put Option Buyer&lt;&#x2F;li&gt;
&lt;li&gt;看跌期权卖方: Put Option Seller&lt;&#x2F;li&gt;
&lt;li&gt;杠杆效应: Leverage Effect&lt;&#x2F;li&gt;
&lt;li&gt;美式期权: American Option&lt;&#x2F;li&gt;
&lt;li&gt;欧式期权: European Option&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;xing-quan-he-ping-cang&quot;&gt;行权和平仓&lt;a class=&quot;zola-anchor&quot; href=&quot;#xing-quan-he-ping-cang&quot; aria-label=&quot;Anchor link for: xing-quan-he-ping-cang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;xing-quan-exercise&quot;&gt;行权（Exercise）&lt;a class=&quot;zola-anchor&quot; href=&quot;#xing-quan-exercise&quot; aria-label=&quot;Anchor link for: xing-quan-exercise&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;行权是指期权持有人在期权到期日或之前根据期权合约的条款行使购买（看涨期权）或卖出（看跌期权）标的资产的权利。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;看涨期权（Call Option）: 行权意味着以行权价买入标的资产。例如，若你持有一张行权价为100美元的看涨期权，当标的资产价格上涨至150美元时，你可以行权以100美元的价格买入该资产，然后以市场价格150美元卖出，从中获利。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;看跌期权（Put Option）: 行权意味着以行权价卖出标的资产。例如，若你持有一张行权价为100美元的看跌期权，当标的资产价格下跌至50美元时，你可以行权以100美元的价格卖出该资产，从而避免损失。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;ping-cang-close-the-position&quot;&gt;平仓（Close the Position）&lt;a class=&quot;zola-anchor&quot; href=&quot;#ping-cang-close-the-position&quot; aria-label=&quot;Anchor link for: ping-cang-close-the-position&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;平仓是指在期权到期前通过反向交易来结束持有的期权头寸，从而锁定利润或减少损失。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;买入期权的平仓: 如果你之前买入了期权，可以通过在市场上卖出相同数量的相同期权合约来平仓。平仓后，你将不再持有该期权，获利或亏损取决于期权的买入价和卖出价的差额。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;卖出期权的平仓: 如果你之前卖出了期权，可以通过在市场上买入相同数量的相同期权合约来平仓。平仓后，你将解除行权义务，获利或亏损取决于期权的卖出价和买入价的差额。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;li-zi&quot;&gt;例子&lt;a class=&quot;zola-anchor&quot; href=&quot;#li-zi&quot; aria-label=&quot;Anchor link for: li-zi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;xing-quan-de-li-zi&quot;&gt;行权的例子&lt;a class=&quot;zola-anchor&quot; href=&quot;#xing-quan-de-li-zi&quot; aria-label=&quot;Anchor link for: xing-quan-de-li-zi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;假设你持有一张看涨期权（行权价100美元），当前市场价150美元：&lt;&#x2F;p&gt;
&lt;p&gt;行权: 你选择行使期权，以100美元的价格买入股票，然后以150美元的市场价卖出股票，获得每股50美元的利润（扣除期权成本）。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;ping-cang-de-li-zi&quot;&gt;平仓的例子&lt;a class=&quot;zola-anchor&quot; href=&quot;#ping-cang-de-li-zi&quot; aria-label=&quot;Anchor link for: ping-cang-de-li-zi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;假设你持有一张看涨期权（买入时溢价为5美元），当前市场溢价为50美元：&lt;&#x2F;p&gt;
&lt;p&gt;平仓: 你选择在市场上卖出这张看涨期权，卖出价格为50美元，获得每股45美元的利润（50美元 - 5美元）。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;guan-jian-qu-bie&quot;&gt;关键区别&lt;a class=&quot;zola-anchor&quot; href=&quot;#guan-jian-qu-bie&quot; aria-label=&quot;Anchor link for: guan-jian-qu-bie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;行权: 实际上执行买入或卖出标的资产的权利，需要交割实际的标的资产，适用于期权到期或有意行使权利的情况下。&lt;&#x2F;li&gt;
&lt;li&gt;平仓: 通过市场反向交易了结期权合约，不涉及实际交割标的资产，适用于提前锁定利润或减少损失的情况下。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;考虑到行权需要大量本金，很多投资者在期权交易中选择平仓而不是行权，因为平仓不需要支付买入标的资产的全额成本，只需进行期权合约的买卖。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;行权: 需要支付购买标的资产的本金。&lt;&#x2F;li&gt;
&lt;li&gt;平仓: 通过市场卖出期权合约，无需支付购买标的资产的本金。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;如果没有足够的资金进行行权，或不想实际持有标的资产，可以选择平仓获利。这也是为什么很多投资者在期权到期前选择平仓而不是行权的原因之一。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kan-die-qi-quan-he-zuo-kong-gu-piao-de-qu-bie&quot;&gt;看跌期权和做空股票的区别&lt;a class=&quot;zola-anchor&quot; href=&quot;#kan-die-qi-quan-he-zuo-kong-gu-piao-de-qu-bie&quot; aria-label=&quot;Anchor link for: kan-die-qi-quan-he-zuo-kong-gu-piao-de-qu-bie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;行权：没有借股费用或股息支付，仅损失期权溢价。适用于持有看跌期权的投资者。&lt;&#x2F;li&gt;
&lt;li&gt;做空：涉及借股费用、股息支付和保证金要求。适用于直接借入和卖出股票的投资者。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Invest | 1.股票中的一些术语</title>
          <pubDate>Tue, 28 May 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-05-28-invest-stock/</link>
          <guid>https://inasa.dev/posts/24-05-28-invest-stock/</guid>
          <description xml:base="https://inasa.dev/posts/24-05-28-invest-stock/">&lt;h2 id=&quot;penny-stocks-xian-gu&quot;&gt;penny stocks(仙股)&lt;a class=&quot;zola-anchor&quot; href=&quot;#penny-stocks-xian-gu&quot; aria-label=&quot;Anchor link for: penny-stocks-xian-gu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&quot;penny stocks&quot; 通常指每股交易价格在5美元或以下的股票。这些股票通常在小型公司、初创企业或财务状况不佳的公司中较为常见。特点和投资风险：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;低价格：每股价格低于5美元，有些甚至低于1美元。&lt;&#x2F;li&gt;
&lt;li&gt;高波动性：价格波动大，可能在短时间内大幅上涨或下跌。&lt;&#x2F;li&gt;
&lt;li&gt;流动性低：交易量较小，买卖可能不容易成交。&lt;&#x2F;li&gt;
&lt;li&gt;信息披露不充分：许多“penny stocks”公司在信息披露上不如大公司规范，信息不透明。&lt;&#x2F;li&gt;
&lt;li&gt;高风险高回报：虽然有可能获得高回报，但风险也非常高，可能面临本金亏损的风险。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;blue-chip-stocks-lan-chou-gu&quot;&gt;Blue Chip Stocks(蓝筹股)&lt;a class=&quot;zola-anchor&quot; href=&quot;#blue-chip-stocks-lan-chou-gu&quot; aria-label=&quot;Anchor link for: blue-chip-stocks-lan-chou-gu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;蓝筹股（Blue Chip Stocks）是指那些在市场中占据主导地位、财务状况良好、业绩稳定的大型公司的股票。这些公司通常有着较长的经营历史，具备良好的声誉和强劲的竞争力。蓝筹股被视为相对安全的投资，因其稳定的收益和较低的风险特征，以下是蓝筹股的一些主要特点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;稳定性：蓝筹股公司的经营和盈利状况通常比较稳定，能够抵御经济周期的波动。&lt;&#x2F;li&gt;
&lt;li&gt;良好的财务状况：这些公司通常拥有健康的财务报表，较低的负债水平，和强劲的现金流。&lt;&#x2F;li&gt;
&lt;li&gt;定期派息：蓝筹股公司往往会定期向股东派发股息，提供稳定的收入来源。&lt;&#x2F;li&gt;
&lt;li&gt;行业领导者：蓝筹股公司通常在其所属行业中占据领先地位，具有较高的市场份额和竞争优势。&lt;&#x2F;li&gt;
&lt;li&gt;品牌和声誉：这些公司拥有强大的品牌和良好的声誉，在市场上具有较高的认知度和信任度。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;一些典型的蓝筹股公司包括：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Apple Inc. (AAPL)：全球领先的科技公司，知名产品包括iPhone、iPad和Mac电脑。&lt;&#x2F;li&gt;
&lt;li&gt;Microsoft Corporation (MSFT)：全球最大的计算机软件公司，Windows操作系统和Office办公软件的开发商。&lt;&#x2F;li&gt;
&lt;li&gt;The Coca-Cola Company (KO)：全球最大的饮料公司之一，旗下拥有众多知名品牌。&lt;&#x2F;li&gt;
&lt;li&gt;Johnson &amp;amp; Johnson (JNJ)：全球领先的医疗保健公司，提供药品、医疗设备和消费品。&lt;&#x2F;li&gt;
&lt;li&gt;Walmart Inc. (WMT)：全球最大的零售商，经营广泛的商品和服务。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;优点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;稳定收益：由于公司经营稳定，蓝筹股通常提供稳定的股息回报。&lt;&#x2F;li&gt;
&lt;li&gt;较低风险：相比小型公司股票，蓝筹股的波动性较小，风险较低。&lt;&#x2F;li&gt;
&lt;li&gt;长期增长：蓝筹股公司的持续盈利能力和市场地位，通常会带来长期的资本增值。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;缺点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;增长潜力有限：由于蓝筹股公司规模庞大，其增长速度可能不如小型快速增长的公司。&lt;&#x2F;li&gt;
&lt;li&gt;价格较高：蓝筹股的价格通常较高，可能对部分投资者的投资成本带来一定压力。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;growth-stocks-cheng-chang-gu&quot;&gt;Growth Stocks(成长股)&lt;a class=&quot;zola-anchor&quot; href=&quot;#growth-stocks-cheng-chang-gu&quot; aria-label=&quot;Anchor link for: growth-stocks-cheng-chang-gu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;成长股（Growth Stocks）指的是那些预期未来收入和利润将会以高于市场平均水平的速度增长的公司的股票。这些公司通常处于快速发展的行业或市场，有着显著的增长潜力。成长股通常不以高股息回报吸引投资者，而是通过资本增值来实现收益。以下是成长股的主要特点和一些例子：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;高增长潜力：成长股公司的收入和利润增长速度通常高于行业平均水平，预期未来将有显著增长。&lt;&#x2F;li&gt;
&lt;li&gt;低股息或不派息：这些公司通常将利润再投资于业务扩展和创新，而不是向股东派发股息。&lt;&#x2F;li&gt;
&lt;li&gt;较高的市盈率：由于市场对其未来增长的预期，成长股的市盈率（P&#x2F;E比率）通常较高。&lt;&#x2F;li&gt;
&lt;li&gt;创新和研发投入：成长股公司通常在技术、产品和市场创新方面投入大量资源，以保持竞争优势。&lt;&#x2F;li&gt;
&lt;li&gt;波动性较大：成长股的价格波动性较高，可能会随着市场情绪和公司业绩预期的变化而大幅波动。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;一些典型的成长股公司包括：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Amazon.com, Inc. (AMZN)：全球最大的在线零售商之一，业务涵盖电子商务、云计算、人工智能等多个领域。&lt;&#x2F;li&gt;
&lt;li&gt;Tesla, Inc. (TSLA)：电动汽车和可再生能源领域的领导者，以创新和技术驱动的快速增长著称。&lt;&#x2F;li&gt;
&lt;li&gt;NVIDIA Corporation (NVDA)：全球领先的图形处理器（GPU）制造商，广泛应用于游戏、数据中心和人工智能领域。&lt;&#x2F;li&gt;
&lt;li&gt;Netflix, Inc. (NFLX)：全球知名的流媒体服务提供商，通过原创内容和全球扩展实现快速增长。&lt;&#x2F;li&gt;
&lt;li&gt;Salesforce.com, Inc. (CRM)：领先的云计算和客户关系管理（CRM）软件提供商，持续增长的订阅收入推动公司快速发展。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;优点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;高回报潜力：如果公司成功实现预期增长，成长股可能带来显著的资本增值。&lt;&#x2F;li&gt;
&lt;li&gt;创新驱动：成长股公司通常在行业中处于创新前沿，有机会通过新技术和新市场获得竞争优势。&lt;&#x2F;li&gt;
&lt;li&gt;市场需求：成长股公司往往处于高需求增长的行业，如科技、医疗保健和绿色能源。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;缺点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;高风险：由于市场预期较高，成长股价格波动性大，投资风险较高。&lt;&#x2F;li&gt;
&lt;li&gt;缺乏股息收入：成长股公司通常不派发股息，投资者主要依赖资本增值。&lt;&#x2F;li&gt;
&lt;li&gt;依赖市场情绪：成长股的表现容易受到市场情绪和宏观经济因素的影响，存在较大不确定性。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;value-stocks-jia-zhi-gu&quot;&gt;Value Stocks(价值股)&lt;a class=&quot;zola-anchor&quot; href=&quot;#value-stocks-jia-zhi-gu&quot; aria-label=&quot;Anchor link for: value-stocks-jia-zhi-gu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;价值股（Value Stocks）是指那些股价被认为低于其内在价值的公司股票。投资者认为这些股票被市场低估，因此有潜力在未来增值。价值股通常具有稳健的基本面，如强劲的财务状况、稳定的盈利和良好的现金流，以下是价值股的主要特点和一些例子：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;低市盈率（P&#x2F;E）：价值股通常具有较低的市盈率，表明其股票价格相对于每股收益较低。&lt;&#x2F;li&gt;
&lt;li&gt;高股息收益率：许多价值股公司会向股东派发较高的股息，提供稳定的收入来源。&lt;&#x2F;li&gt;
&lt;li&gt;稳健的基本面：价值股公司通常具有良好的财务状况，稳定的盈利能力和强劲的现金流。&lt;&#x2F;li&gt;
&lt;li&gt;被市场低估：这些股票通常被认为被市场忽视或低估，原因可能包括市场情绪、短期问题或行业周期等。&lt;&#x2F;li&gt;
&lt;li&gt;较低波动性：相对于成长股，价值股的价格波动性较小，风险较低。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;一些典型的价值股公司包括：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Johnson &amp;amp; Johnson (JNJ)：全球领先的医疗保健公司，长期以来财务稳健，盈利稳定。&lt;&#x2F;li&gt;
&lt;li&gt;Procter &amp;amp; Gamble Co. (PG)：全球知名的消费品公司，旗下拥有众多知名品牌，财务状况良好。&lt;&#x2F;li&gt;
&lt;li&gt;Coca-Cola Co. (KO)：全球最大的饮料公司之一，具有稳定的市场份额和强劲的品牌影响力。&lt;&#x2F;li&gt;
&lt;li&gt;JPMorgan Chase &amp;amp; Co. (JPM)：美国最大的银行之一，拥有稳健的资产负债表和持续的盈利能力。&lt;&#x2F;li&gt;
&lt;li&gt;Exxon Mobil Corporation (XOM)：全球最大的石油和天然气公司之一，具备强大的资源和财务实力。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;优点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;潜在升值空间：由于被市场低估，价值股有潜力在市场调整后实现价格升值。&lt;&#x2F;li&gt;
&lt;li&gt;股息收益：许多价值股公司提供较高的股息，增加投资者的现金收入。&lt;&#x2F;li&gt;
&lt;li&gt;相对较低风险：价值股公司的基本面通常较为稳健，股价波动性较低，投资风险相对较低。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;缺点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;增长速度较慢：价值股公司的增长速度通常较慢，相对于成长股，资本增值潜力较小。&lt;&#x2F;li&gt;
&lt;li&gt;市场回归周期较长：价值股可能需要较长时间才能被市场重新认识和评估，投资回报可能需要较长时间才能实现。&lt;&#x2F;li&gt;
&lt;li&gt;依赖市场情绪：尽管基本面良好，价值股仍然可能受到市场情绪和短期市场波动的影响。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;投资价值股通常需要投资者具备较长的投资视野和耐心，以下是一些常见的价值投资策略：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;基本面分析：仔细分析公司的财务报表、盈利能力、现金流和债务水平，寻找被市场低估的股票。&lt;&#x2F;li&gt;
&lt;li&gt;估值比率：使用市盈率、市净率（P&#x2F;B）和股息收益率等估值比率，评估股票是否被低估。&lt;&#x2F;li&gt;
&lt;li&gt;长期持有：价值投资者通常采取长期持有策略，相信市场最终会修正其错误定价，实现股票的内在价值。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;red-chip-stocks-hong-chou-gu&quot;&gt;Red Chip Stocks(红筹股)&lt;a class=&quot;zola-anchor&quot; href=&quot;#red-chip-stocks-hong-chou-gu&quot; aria-label=&quot;Anchor link for: red-chip-stocks-hong-chou-gu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;红筹股（Red Chip Stocks）是指那些在中国大陆以外注册，但主要业务在中国大陆的公司股票。通常，这些公司在香港证券交易所上市，并受到中资背景的支持。红筹股公司通常是由中国的国有企业或有强大政府背景的企业改制而来，以下是红筹股的主要特点和一些例子：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;中资背景：红筹股公司通常与中国政府或国有企业有密切的关系，可能享有政策支持和资源优势。&lt;&#x2F;li&gt;
&lt;li&gt;主要业务在中国大陆：尽管公司在中国大陆以外注册，其主要收入和业务运营都在中国大陆。&lt;&#x2F;li&gt;
&lt;li&gt;香港上市：红筹股主要在香港证券交易所上市，是香港市场的一部分。&lt;&#x2F;li&gt;
&lt;li&gt;政策影响：红筹股公司的业务和财务表现可能受到中国政府政策变化的影响较大。&lt;&#x2F;li&gt;
&lt;li&gt;较强的财务状况：许多红筹股公司具有较强的财务状况和盈利能力，受益于中国经济的快速发展。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;一些典型的红筹股公司包括：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;中国移动（China Mobile, 0941.HK）：全球最大的移动通信运营商之一，主要业务在中国大陆。&lt;&#x2F;li&gt;
&lt;li&gt;中国联通（China Unicom, 0762.HK）：中国主要的电信运营商之一，提供移动通信和固定通信服务。&lt;&#x2F;li&gt;
&lt;li&gt;中国海洋石油（CNOOC, 0883.HK）：中国主要的海上石油和天然气生产商之一。&lt;&#x2F;li&gt;
&lt;li&gt;华润啤酒（China Resources Beer, 0291.HK）：中国最大的啤酒生产商之一，拥有多个知名品牌。&lt;&#x2F;li&gt;
&lt;li&gt;招商局港口（China Merchants Port, 0144.HK）：中国主要的港口运营商之一，管理多个重要的港口设施。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;优点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;受益于中国经济增长：红筹股公司的主要业务在中国大陆，可以直接受益于中国经济的快速增长和发展。&lt;&#x2F;li&gt;
&lt;li&gt;政策支持：由于与中国政府或国有企业的密切关系，红筹股公司可能享有政策支持和资源优势。&lt;&#x2F;li&gt;
&lt;li&gt;市场认知度高：许多红筹股公司在行业内具有较高的市场认知度和竞争力。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;缺点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;政策风险：红筹股公司的业务和财务表现可能受到中国政府政策变化的影响，政策风险较高。&lt;&#x2F;li&gt;
&lt;li&gt;市场波动性：红筹股的市场价格可能受到宏观经济、政策变化和市场情绪的影响，波动性较大。&lt;&#x2F;li&gt;
&lt;li&gt;跨境监管：由于在中国大陆以外注册，红筹股公司需要遵守跨境的法律和监管要求，可能增加运营复杂性。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;投资红筹股需要考虑以下因素：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;宏观经济环境：关注中国宏观经济的变化和发展趋势，以评估红筹股的潜在表现。&lt;&#x2F;li&gt;
&lt;li&gt;政策动向：密切关注中国政府的政策变化，特别是与红筹股公司业务相关的政策。&lt;&#x2F;li&gt;
&lt;li&gt;公司基本面：分析红筹股公司的财务状况、盈利能力和市场竞争力，选择具备良好基本面的公司。&lt;&#x2F;li&gt;
&lt;li&gt;市场情绪：了解市场对红筹股的情绪和预期，合理评估投资风险和回报。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;tech-stocks-ke-ji-gu&quot;&gt;Tech Stocks(科技股)&lt;a class=&quot;zola-anchor&quot; href=&quot;#tech-stocks-ke-ji-gu&quot; aria-label=&quot;Anchor link for: tech-stocks-ke-ji-gu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;科技股（Tech Stocks）是指那些从事技术、创新和研发的公司的股票。这些公司通常在快速发展的行业中运营，如信息技术、软件开发、硬件制造、互联网服务、半导体、人工智能和生物科技等。科技股以其高增长潜力和创新能力而著称，以下是科技股的主要特点和一些例子：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;高增长潜力：科技公司通常处于快速发展的行业，具有高增长潜力。&lt;&#x2F;li&gt;
&lt;li&gt;高研发投入：科技股公司通常在研发上投入大量资源，以推动创新和技术进步。&lt;&#x2F;li&gt;
&lt;li&gt;高波动性：由于市场对科技股未来增长的预期较高，其股价波动性也较大。&lt;&#x2F;li&gt;
&lt;li&gt;创新驱动：科技公司往往通过创新和新技术的应用来获得竞争优势。&lt;&#x2F;li&gt;
&lt;li&gt;风险与回报并存：尽管科技股可能带来高回报，但其风险也较高，尤其是面对技术迭代和市场竞争。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;一些典型的科技股公司包括：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Apple Inc. (AAPL)：全球领先的消费电子产品公司，知名产品包括iPhone、iPad和Mac。&lt;&#x2F;li&gt;
&lt;li&gt;Microsoft Corporation (MSFT)：全球最大的计算机软件公司，主要产品包括Windows操作系统和Office办公软件。&lt;&#x2F;li&gt;
&lt;li&gt;Alphabet Inc. (GOOGL)：谷歌的母公司，全球最大的搜索引擎和互联网服务提供商。&lt;&#x2F;li&gt;
&lt;li&gt;Amazon.com, Inc. (AMZN)：全球最大的在线零售商之一，同时也是云计算服务的领导者。&lt;&#x2F;li&gt;
&lt;li&gt;NVIDIA Corporation (NVDA)：全球领先的图形处理器（GPU）制造商，广泛应用于游戏、数据中心和人工智能领域。&lt;&#x2F;li&gt;
&lt;li&gt;Tesla, Inc. (TSLA)：电动汽车和可再生能源领域的领导者，以创新和技术驱动的快速增长著称。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;优点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;高回报潜力：科技股具有高增长潜力，成功的公司可能带来显著的资本增值。&lt;&#x2F;li&gt;
&lt;li&gt;创新驱动：科技股公司通常在行业中处于创新前沿，有机会通过新技术和新市场获得竞争优势。&lt;&#x2F;li&gt;
&lt;li&gt;市场需求：科技行业的快速发展和技术进步带来持续的市场需求。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;缺点：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;高风险：科技股价格波动性大，投资风险较高，尤其是在技术迭代和市场竞争激烈的情况下。&lt;&#x2F;li&gt;
&lt;li&gt;依赖市场情绪：科技股的表现容易受到市场情绪和宏观经济因素的影响，存在较大不确定性。&lt;&#x2F;li&gt;
&lt;li&gt;估值较高：由于市场对其未来增长的预期，科技股的估值通常较高。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;投资科技股需要关注以下因素：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;技术趋势：了解和跟踪行业中的最新技术趋势和发展动态，以评估科技公司的创新潜力。&lt;&#x2F;li&gt;
&lt;li&gt;公司基本面：分析科技公司的财务状况、研发投入、市场份额和竞争力，选择具备良好基本面的公司。&lt;&#x2F;li&gt;
&lt;li&gt;市场情绪：了解市场对科技股的预期和情绪，合理评估投资风险和回报。&lt;&#x2F;li&gt;
&lt;li&gt;长期视野：由于科技股的高波动性和不确定性，投资者应采取长期视野，耐心等待市场的回报。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>MySQL | InnoDB Page Compression</title>
          <pubDate>Thu, 25 Apr 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-04-25-mysql-innodb-page-compression/</link>
          <guid>https://inasa.dev/posts/24-04-25-mysql-innodb-page-compression/</guid>
          <description xml:base="https://inasa.dev/posts/24-04-25-mysql-innodb-page-compression/">&lt;h1 id=&quot;innodb-page-compression&quot;&gt;InnoDB Page Compression&lt;a class=&quot;zola-anchor&quot; href=&quot;#innodb-page-compression&quot; aria-label=&quot;Anchor link for: innodb-page-compression&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;InnoDB&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 支持对驻留在 &lt;strong&gt;&lt;code&gt;file-per-table&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 表空间中的表进行页面级压缩 &lt;strong&gt;&lt;code&gt;page-level compression&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;此功能称为透明页面压缩 &lt;strong&gt;&lt;code&gt;Transparent Page Compression&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;通过在 &lt;strong&gt;&lt;code&gt;CREATE TABLE&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 或 &lt;strong&gt;&lt;code&gt;ALTER TABLE&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 中指定 &lt;strong&gt;&lt;code&gt;COMPRESSION&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 属性，可启用页面压缩。&lt;&#x2F;p&gt;
&lt;p&gt;支持的压缩算法包括 &lt;strong&gt;&lt;code&gt;Zlib&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 和 &lt;strong&gt;&lt;code&gt;LZ4&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;how-page-compression-works&quot;&gt;&lt;strong&gt;How Page Compression Works&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-page-compression-works&quot; aria-label=&quot;Anchor link for: how-page-compression-works&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;写入页面时，会使用指定的压缩算法对其进行压缩。压缩后的数据被写入磁盘，打孔机制会释放页面末尾的空块。如果压缩失败，数据将按原样写出。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;hole-punch-size-on-linux&quot;&gt;&lt;strong&gt;Hole Punch Size on Linux&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#hole-punch-size-on-linux&quot; aria-label=&quot;Anchor link for: hole-punch-size-on-linux&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;在 &lt;strong&gt;&lt;code&gt;Linux&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 系统中，文件系统块大小是用于打孔的单位大小。&lt;&#x2F;p&gt;
&lt;p&gt;因此，只有当页面数据被压缩到小于或等于 &lt;strong&gt;&lt;code&gt;InnoDB&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 页面大小减去文件系统块大小时，页面压缩才会起作用。&lt;&#x2F;p&gt;
&lt;p&gt;例如，如果 &lt;strong&gt;&lt;code&gt;innodb_page_size=16K&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;，而文件系统块大小为 &lt;strong&gt;&lt;code&gt;4K&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;，则页面数据必须压缩到小于或等于 &lt;strong&gt;&lt;code&gt;12K&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 才能打孔。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;enabling-page-compression&quot;&gt;&lt;strong&gt;Enabling Page Compression&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#enabling-page-compression&quot; aria-label=&quot;Anchor link for: enabling-page-compression&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;要启用页面压缩，请在 &lt;strong&gt;&lt;code&gt;CREATE TABLE&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 语句中指定 &lt;strong&gt;&lt;code&gt;COMPRESSION&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 属性。例如&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-create z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;CREATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;TABLE&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-sql&quot;&gt;t1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; (c1 &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;INT&lt;&#x2F;span&gt;) COMPRESSION&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;zlib&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;也可以在 &lt;strong&gt;&lt;code&gt;ALTER&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 表语句中启用页面压缩。&lt;&#x2F;p&gt;
&lt;p&gt;但是，&lt;strong&gt;&lt;code&gt;ALTER TABLE ... COMPRESSION&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 只更新表空间压缩属性。&lt;&#x2F;p&gt;
&lt;p&gt;设置新压缩算法后向表空间的写入将使用新设置，但要将新压缩算法应用到现有页面，必须使用 &lt;strong&gt;&lt;code&gt;OPTIMIZE TABLE&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 重建表。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-alter z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;ALTER&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-table z-sql&quot;&gt;TABLE&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;t1 COMPRESSION&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;zlib&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;OPTIMIZE TABLE t1;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;出现 &lt;strong&gt;&lt;code&gt;Table does not support optimize, doing recreate + analyze instead&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 是正常的，参考&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;dev.mysql.com&#x2F;doc&#x2F;refman&#x2F;8.0&#x2F;en&#x2F;optimize-table.html&quot;&gt;https:&#x2F;&#x2F;dev.mysql.com&#x2F;doc&#x2F;refman&#x2F;8.0&#x2F;en&#x2F;optimize-table.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h1 id=&quot;disabling-page-compression&quot;&gt;&lt;strong&gt;Disabling Page Compression&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#disabling-page-compression&quot; aria-label=&quot;Anchor link for: disabling-page-compression&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;要禁用页面压缩，请使用 &lt;strong&gt;&lt;code&gt;ALTER&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 表设置 &lt;strong&gt;&lt;code&gt;COMPRESSION=None&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;设置 &lt;strong&gt;&lt;code&gt;COMPRESSION=None&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 后，写入表空间时不再使用页面压缩。&lt;&#x2F;p&gt;
&lt;p&gt;要解压缩现有页面，必须在设置 &lt;strong&gt;&lt;code&gt;COMPRESSION=None&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 后使用 &lt;strong&gt;&lt;code&gt;OPTIMIZE TABLE&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 重建表。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-alter z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;ALTER&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-table z-sql&quot;&gt;TABLE&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;t1 COMPRESSION&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;None&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;OPTIMIZE TABLE t1;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;page-compression-metadata&quot;&gt;&lt;strong&gt;Page Compression Metadata&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#page-compression-metadata&quot; aria-label=&quot;Anchor link for: page-compression-metadata&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;页面压缩元数据可在 &lt;strong&gt;&lt;code&gt;Information Schema. INNODB_TABLESPACES&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 表的以下列中找到：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;FS_BLOCK_SIZE&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 文件系统块大小，即用于打孔的单位大小。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;FILE_SIZE&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 文件的表观大小，表示未压缩文件的最大大小。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ALLOCATED_SIZE&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 文件的实际大小，即在磁盘上分配的空间大小&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;note&quot;&gt;Note&lt;a class=&quot;zola-anchor&quot; href=&quot;#note&quot; aria-label=&quot;Anchor link for: note&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;在类 Unix 系统上，&lt;strong&gt;&lt;code&gt;ls -l tablespace_name.ibd&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 显示的文件大小（相当于 &lt;strong&gt;&lt;code&gt;FILE_SIZE&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;）的字节数。要查看磁盘上分配的实际空间大小（相当于 &lt;strong&gt;&lt;code&gt;ALLOCATED_SIZE&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;），请使用 &lt;strong&gt;&lt;code&gt;du --block-size=1tablespace_name.ibd&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;。选项 &lt;strong&gt;&lt;code&gt;--block-size=1&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 会以字节而非块为单位打印分配的空间，以便与 &lt;strong&gt;&lt;code&gt;ls -l&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 输出进行比较。&lt;&#x2F;p&gt;
&lt;p&gt;使用 &lt;strong&gt;&lt;code&gt;SHOW CREATE TABLE&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 查看当前页面压缩设置（&lt;strong&gt;&lt;code&gt;Zlib&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;、&lt;strong&gt;&lt;code&gt;Lz4&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 或无）。一个表可能包含不同压缩设置的混合页面。&lt;&#x2F;p&gt;
&lt;p&gt;在下面的示例中，将从 &lt;strong&gt;&lt;code&gt;Information Schema. INNODB_TABLESPACES&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 表中获取 &lt;strong&gt;&lt;code&gt;Employees&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 表的页面压缩元数据。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;#&lt;&#x2F;span&gt; Create the employees table with Zlib page compression
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-meta z-create z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-other z-create z-sql&quot;&gt;CREATE&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-sql&quot;&gt;TABLE&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-toc-list z-full-identifier z-sql&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-sql&quot;&gt;employees&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; (
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    emp_no      &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;INT&lt;&#x2F;span&gt;             &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;NOT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    birth_date  &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;DATE&lt;&#x2F;span&gt;            &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;NOT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    first_name  &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;VARCHAR&lt;&#x2F;span&gt;(&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;14&lt;&#x2F;span&gt;)     &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;NOT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    last_name   &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;VARCHAR&lt;&#x2F;span&gt;(&lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;16&lt;&#x2F;span&gt;)     &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;NOT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    gender      ENUM (&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;M&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;,&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;F&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;)  &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;NOT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    hire_date   &lt;span class=&quot;z-storage z-type z-sql&quot;&gt;DATE&lt;&#x2F;span&gt;            &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;NOT&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-sql&quot;&gt;NULL&lt;&#x2F;span&gt;,
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;    &lt;span class=&quot;z-storage z-modifier z-sql&quot;&gt;PRIMARY KEY&lt;&#x2F;span&gt; (emp_no)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;) COMPRESSION&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;zlib&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;#&lt;&#x2F;span&gt; Insert data (not shown)
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;#&lt;&#x2F;span&gt; Query page compression metadata in INFORMATION_SCHEMA.INNODB_TABLESPACES
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;mysql&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT&lt;&#x2F;span&gt; SPACE, NAME, FS_BLOCK_SIZE, FILE_SIZE, ALLOCATED_SIZE &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;       &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;INFORMATION_SCHEMA&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;INNODB_TABLESPACES&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;WHERE&lt;&#x2F;span&gt; NAME&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;employees&#x2F;employees&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;\G
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;1&lt;&#x2F;span&gt;. row &lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language z-star z-sql&quot;&gt;*&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;SPACE: &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;45&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;NAME: employees&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;&#x2F;&lt;&#x2F;span&gt;employees
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;FS_BLOCK_SIZE: &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;4096&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;FILE_SIZE: &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;23068672&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;ALLOCATED_SIZE: &lt;span class=&quot;z-constant z-numeric z-sql&quot;&gt;19415040&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Employees&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 表的页面压缩元数据显示，表观文件大小为 23068672 字节，而实际文件大小（使用页面压缩）为 19415040 字节。文件系统块大小为4096字节，这是用于打洞的块大小。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;identifying-tables-using-page-compression&quot;&gt;&lt;strong&gt;Identifying Tables Using Page Compression&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#identifying-tables-using-page-compression&quot; aria-label=&quot;Anchor link for: identifying-tables-using-page-compression&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;要识别已启用页面压缩的表，可以检查 &lt;strong&gt;&lt;code&gt;Information Schema.TABLES&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 表的 &lt;strong&gt;&lt;code&gt;CREATE_OPTIONS&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 列中是否有使用 &lt;strong&gt;&lt;code&gt;COMPRESSION&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 属性定义的表：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;sql&quot; class=&quot;language-sql z-code&quot;&gt;&lt;code class=&quot;language-sql&quot; data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;mysql&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;SELECT&lt;&#x2F;span&gt; TABLE_NAME, TABLE_SCHEMA, CREATE_OPTIONS &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;FROM&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-database-name z-sql&quot;&gt;INFORMATION_SCHEMA&lt;&#x2F;span&gt;.&lt;span class=&quot;z-constant z-other z-table-name z-sql&quot;&gt;TABLES&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;       &lt;span class=&quot;z-keyword z-other z-DML z-sql&quot;&gt;WHERE&lt;&#x2F;span&gt; CREATE_OPTIONS &lt;span class=&quot;z-keyword z-operator z-logical z-sql&quot;&gt;LIKE&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;%COMPRESSION=%&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;+&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt;----------+--------------+--------------------+
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;| TABLE_NAME | TABLE_SCHEMA | CREATE_OPTIONS     |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;+&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt;----------+--------------+--------------------+
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;| employees  | test         | COMPRESSION&lt;span class=&quot;z-keyword z-operator z-comparison z-sql&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;zlib&lt;span class=&quot;z-punctuation z-definition z-string z-end z-sql&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; |
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-sql&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-math z-sql&quot;&gt;+&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-double-dash z-sql&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-sql&quot;&gt;--&lt;&#x2F;span&gt;----------+--------------+--------------------+
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;page-compression-limitations-and-usage-notes&quot;&gt;&lt;strong&gt;Page Compression Limitations and Usage Notes&lt;&#x2F;strong&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#page-compression-limitations-and-usage-notes&quot; aria-label=&quot;Anchor link for: page-compression-limitations-and-usage-notes&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;如果文件系统块大小（或 Windows 上的压缩单元大小）* 2 &amp;gt; innodb_page_size，则会禁用页面压缩。&lt;&#x2F;li&gt;
&lt;li&gt;共享表空间（包括系统表空间、临时表空间和常规表空间）中的表不支持页面压缩。&lt;&#x2F;li&gt;
&lt;li&gt;undo log tablespaces不支持页面压缩。&lt;&#x2F;li&gt;
&lt;li&gt;redo log pages不支持页面压缩。&lt;&#x2F;li&gt;
&lt;li&gt;用于空间索引的 R 树页面不会被压缩。&lt;&#x2F;li&gt;
&lt;li&gt;属于压缩表（ROW_FORMAT=COMPRESSED）的页面保持不变。&lt;&#x2F;li&gt;
&lt;li&gt;在恢复过程中，更新的页面会以未压缩的形式写出。&lt;&#x2F;li&gt;
&lt;li&gt;在不支持所用压缩算法的服务器上加载页面压缩的表空间会导致 I&#x2F;O 错误。&lt;&#x2F;li&gt;
&lt;li&gt;在降级到不支持页面压缩的早期 MySQL 版本之前，请解压缩使用页面压缩功能的表。要解压缩表，请运行 ALTER TABLE ... COMPRESSION=None 和 OPTIMIZE TABLE。&lt;&#x2F;li&gt;
&lt;li&gt;如果使用的压缩算法在 Linux 和 Windows 服务器上都可用，则页面压缩的表空间可在 Linux 和 Windows 服务器之间复制。f&lt;&#x2F;li&gt;
&lt;li&gt;在将页面压缩的表空间文件从一台主机移动到另一台主机时，需要一个能保留稀疏文件的实用程序来保留页面压缩。&lt;&#x2F;li&gt;
&lt;li&gt;与其他平台相比，在使用 NVMFS 的 Fusion-io 硬件上可以实现更好的页面压缩效果，因为 NVMFS 就是为利用打孔功能而设计的。&lt;&#x2F;li&gt;
&lt;li&gt;使用页面压缩功能时，如果 InnoDB 页面大小较大，而文件系统块大小相对较小，可能会导致写放大。例如，最大 InnoDB 页面大小为 64KB，文件系统块大小为 4KB，这可能会提高压缩率，但也可能会增加对缓冲池的需求，导致 I&#x2F;O 增加和潜在的写放大。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;dev.mysql.com&#x2F;doc&#x2F;refman&#x2F;8.0&#x2F;en&#x2F;innodb-page-compression.html&quot;&gt;https:&#x2F;&#x2F;dev.mysql.com&#x2F;doc&#x2F;refman&#x2F;8.0&#x2F;en&#x2F;innodb-page-compression.html&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;dev.mysql.com&#x2F;doc&#x2F;refman&#x2F;8.0&#x2F;en&#x2F;optimize-table.html&quot;&gt;https:&#x2F;&#x2F;dev.mysql.com&#x2F;doc&#x2F;refman&#x2F;8.0&#x2F;en&#x2F;optimize-table.html&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;3855489&#x2F;cant-optimize-innodb-table&quot;&gt;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;3855489&#x2F;cant-optimize-innodb-table&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>转载 | Hardware Memory Models</title>
          <pubDate>Wed, 03 Apr 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-04-03-memory-model-1/</link>
          <guid>https://inasa.dev/posts/24-04-03-memory-model-1/</guid>
          <description xml:base="https://inasa.dev/posts/24-04-03-memory-model-1/">&lt;h1 id=&quot;hardware-memory-models&quot;&gt;Hardware Memory Models&lt;a class=&quot;zola-anchor&quot; href=&quot;#hardware-memory-models&quot; aria-label=&quot;Anchor link for: hardware-memory-models&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;h1 id=&quot;introduction-a-fairy-tale-endingdao-yan-tong-hua-jie-ju&quot;&gt;Introduction: A Fairy Tale, Ending导言： 童话，结局&lt;a class=&quot;zola-anchor&quot; href=&quot;#introduction-a-fairy-tale-endingdao-yan-tong-hua-jie-ju&quot; aria-label=&quot;Anchor link for: introduction-a-fairy-tale-endingdao-yan-tong-hua-jie-ju&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;blockquote&gt;
&lt;p&gt;A long time ago, when everyone wrote single-threaded programs, one of the most eﬀective ways to make a program run faster was to sit back and do nothing. Optimizations in the next generation of hardware and the next generation of compilers would make the program run exactly as before, just faster. During this fairy-tale period, there was an easy test for whether an optimization was valid: if programmers couldn’t tell the diﬀerence (except for the speedup) between the unoptimized and optimized execution of a valid program, then the optimization was valid. That is, valid optimizations do not change the behavior of valid programs.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;很久以前，当每个人都在编写单线程程序时，要想让程序运行得更快，最有效的方法之一就是坐视不管。下一代硬件和下一代编译器的优化会让程序运行得和以前一模一样，只是速度更快而已。在这个童话般的时期，有一个简单的测试方法来检验优化是否有效：如果程序员无法分辨一个有效程序在未优化和优化后执行的区别（除了速度提升），那么这个优化就是有效的。也就是说，有效的优化不会改变有效程序的行为。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;One sad day, years ago, the hardware engineers’ magic spells for making individual processors faster and faster stopped working. In response, they found a new magic spell that let them create computers with more and more processors, and operating systems exposed this hardware parallelism to programmers in the abstraction of threads. This new magic spell—multiple processors made available in the form of operating-system threads—worked much better for the hardware engineers, but it created signiﬁcant problems for language designers, compiler writers and programmers.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;多年前的一个悲伤日子，硬件工程师们让单个处理器越来越快的魔咒失灵了。为此，他们找到了一个新的法宝，可以让他们创造出拥有越来越多处理器的计算机，而操作系统则以线程的抽象形式将这种硬件并行性展现给程序员。这个新法术--以操作系统线程的形式提供多个处理器--对硬件工程师来说效果更好，但却给语言设计者、编译器编写者和程序员带来了巨大的问题。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Many hardware and compiler optimizations that were invisible (and therefore valid) in single-threaded programs produce visible changes in multithreaded programs. If valid optimizations do not change the behavior of valid programs, then either these optimizations or the existing programs must be declared invalid. Which will it be, and how can we decide?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;许多在单线程程序中不可见（因此有效）的硬件和编译器优化，在多线程程序中会产生可见的变化。如果有效的优化不会改变有效程序的行为，那么这些优化或现有程序都必须宣布无效。究竟是哪种情况，我们又该如何判断呢？&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here is a simple example program in a C-like language. In this program and in all programs we will consider, all variables are initially set to zero.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;下面是一个类似 C 语言的简单示例程序。在这个程序中，以及在我们将要讨论的所有程序中，所有变量的初始值都是零。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;If thread 1 and thread 2, each running on its own dedicated processor, both run to completion, can this program print 0?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;如果线程 1 和线程 2 都运行在各自专用的处理器上，并且都运行完成，这个程序能打印 0 吗？&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;It depends. It depends on the hardware, and it depends on the compiler. A direct line-for-line translation to assembly run on an x86 multiprocessor will always print 1. But a direct line-for-line translation to assembly run on an ARM or POWER multiprocessor can print 0. Also, no matter what the underlying hardware, standard compiler optimizations could make this program print 0 or go into an inﬁnite loop.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;这要看情况。这取决于硬件，也取决于编译器。在 x86 多处理器上运行的汇编程序逐行直接转换总是打印 1，但在 ARM 或 POWER 多处理器上运行的汇编程序逐行直接转换可能打印 0。但是，在 ARM 或 POWER 多处理器上直接逐行转换为汇编程序运行时，可能会打印 0。此外，无论底层硬件如何，标准编译器优化都可能使该程序打印 0 或进入一个无限循环。(进入无限循环应该是由于内存可见性，没有使用适当同步机制)&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;“It depends” is not a happy ending. Programmers need a clear answer to whether a program will continue to work with new hardware and new compilers. And hardware designers and compiler developers need a clear answer to how precisely the hardware and compiled code are allowed to behave when executing a given program. Because the main issue here is the visibility and consistency of changes to data stored in memory, that contract is called the memory consistency model or just memory model.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&quot;看情况而定 &quot;不是一个好的结局。程序员需要一个明确的答案，以确定程序是否能在新硬件和新编译器下继续运行。而硬件设计人员和编译器开发人员也需要一个明确的答案，即在执行特定程序时，硬件和编译后的代码可以有怎样的精确行为。因为这里的主要问题是存储在内存中的数据变化的可见性和一致性，所以这种契约被称为内存一致性模型或内存模型。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Originally, the goal of a memory model was to deﬁne what hardware guaranteed to a programmer writing assembly code. In that setting, the compiler is not involved. Twenty-ﬁve years ago, people started trying to write memory models deﬁning what a high-level programming language like Java or C++ guarantees to programmers writing code in that language. Including the compiler in the model makes the job of deﬁning a reasonable model much more complicated.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;最初，内存模型的目标是为编写汇编代码的程序员定义硬件保证。在这种情况下，编译器并不参与其中。25 年前，人们开始尝试编写内存模型，确定 Java 或 C++ 等高级编程语言对编写该语言代码的程序员的保证。将编译器包含在模型中，使得建立合理模型的工作变得更加复杂。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This is the ﬁrst of a pair of posts about hardware memory models and programming language memory models, respectively. My goal in writing these posts is to build up background for discussing potential changes we might want to make in Go’s memory model. But to understand where Go is and where we might want to head, ﬁrst we have to understand where other hardware memory models and language memory models are today and the precarious paths they took to get there.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;这是分别关于硬件内存模型和编程语言内存模型的两篇文章中的第一篇。我写这两篇文章的目的是为讨论我们可能希望对 Go 的内存模型进行的潜在修改积累背景资料。但是，要了解 Go 的现状以及我们可能想要的方向，我们首先必须了解其他硬件内存模型和语言内存模型的现状，以及它们在实现目标的过程中所走过的崎岖道路。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Again, this post is about hardware. Let’s assume we are writing assembly language for a multiprocessor computer. What guarantees do programmers need from the computer hardware in order to write correct programs? Computer scientists have been searching for good answers to this question for over forty years.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;还是那句话，这篇文章是关于硬件的。假设我们正在为多处理器计算机编写汇编语言。为了编写出正确的程序，程序员需要计算机硬件提供哪些保证？四十多年来，计算机科学家一直在寻找这个问题的答案。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;sequential-consistency&quot;&gt;Sequential Consistency&lt;a class=&quot;zola-anchor&quot; href=&quot;#sequential-consistency&quot; aria-label=&quot;Anchor link for: sequential-consistency&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Leslie Lamport’s 1979 paper “How to Make a Multiprocessor Computer That &lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;www.microsoft.com&#x2F;en-us&#x2F;research&#x2F;publication&#x2F;make-multiprocessor-computer-correctly-executes-multiprocess-programs&#x2F;&quot;&gt;Correctly Executes Multiprocess Programs&lt;&#x2F;a&gt;” introduced the concept of sequential consistency:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;莱斯利-兰波特在 1979 年发表的论文《如何制造能正确执行多进程程序的多处理器计算机》中提出了顺序一致性的概念：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The customary approach to designing and proving the correctness of multiprocess algorithms for such a computer assumes that the following condition is satisﬁed: the result of any execution is the same as if the operations of all the processors were executed in some sequential order, and the operations of each individual processor appear in this sequence in the order speciﬁed by its program. A multiprocessor satisfying this condition will be called sequentially consistent.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;为这种计算机设计和证明多进程算法正确性的惯常方法假定满足以下条件：任何执行的结果都与所有处理器的操作按某种顺序执行的结果相同，而且每个处理器的操作都按其程序指定的顺序出现在该顺序中。满足这一条件的多处理器被称为顺序一致处理器。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Today we talk about not just computer hardware but also programming languages guaranteeing sequential consistency, when the only possible executions of a program correspond to some kind of interleaving of thread operations into a sequential execution. Sequential consistency is usually considered the ideal model, the one most natural for programmers to work with. It lets you assume programs execute in the order they appear on the page, and the executions of individual threads are simply interleaved in some order but not otherwise rearranged.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;今天，我们谈论的不仅是计算机硬件，还包括保证顺序一致性的编程语言，即程序的唯一可能执行方式是将线程操作交织成顺序执行。顺序一致性通常被认为是理想的模型，是程序员最自然的工作模式。它允许你假设程序按照页面上显示的顺序执行，而单个线程的执行只是按照某种顺序交错进行，但不会以其他方式重新排列。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;One might reasonably question whether sequential consistency should be the ideal model, but that’s beyond the scope of this post. I will note only that considering all possible thread interleavings remains, today as in 1979, “the customary approach to designing and proving the correctness of multiprocess algorithms.” In the intervening four decades, nothing has replaced it.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;我们有理由质疑，顺序一致性是否应该是理想的模式。理想模式，但这超出了本篇文章的讨论范围。我只想指出，考虑所有可能的线程交错，在今天和 1979 年一样，仍然是 &quot;设计和证明多进程算法正确性的惯用方法&quot;。在这四十年间，没有任何东西可以取代它。&lt;&#x2F;p&gt;
&lt;p&gt;Earlier I asked whether this program can print 0:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%201.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;To make the program a bit easier to analyze, let’s remove the loop and the print and ask about the possible results from reading the shared variables:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;为了让程序更容易分析，让我们删除循环和打印，并询问读取共享变量可能产生的结果：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%202.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;We assume every example starts with all shared variables set to zero. Because we’re trying to establish what hardware is allowed to do, we assume that each thread is executing on its own dedicated processor and that there’s no compiler to reorder what happens in the thread: the instructions in the listings are the instructions the processor executes. The name rN denotes a thread-local register, not a shared variable, and we ask whether a particular setting of thread-local registers is possible at the end of an execution.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;我们假设每个示例开始时所有共享变量都设置为零。因为我们试图确定硬件可以做什么，所以我们假设每个线程都在自己专用的处理器上执行，没有编译器对线程中发生的事情重新排序：列表中的指令就是处理器执行的指令。rN 表示线程本地寄存器，而不是共享变量，我们要问的是，在执行结束时，线程本地寄存器的特定设置是否可行。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This kind of question about execution results for a sample program is called a litmus test. Because it has a binary answer—is this outcome possible or not?—a litmus test gives us a clear way to distinguish memory models: if one model allows a particular execution and another does not, the two models are clearly different. Unfortunately, as we will see later, the answer a particular model gives to a particular litmus test is often surprising.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;这种关于示例程序执行结果的问题被称为(litmus test, 美俚语)试金石测试。因为它有两种答案--这个结果是可能的还是不可能的--所以试金石测试为我们提供了一种区分内存模型的明确方法：如果一种模型允许某种特定的执行，而另一种不允许，那么这两种模型显然是不同的。不幸的是，正如我们稍后将看到的，特定模型对特定试金石测试给出的答案往往出人意料。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;If the execution of this litmus test is sequentially consistent, there are only six possible interleavings:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;如果这个试金石的执行是等价一致的，那么只有六种可能的交错：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%203.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Since no interleaving ends with r1 = 1, r2 = 0, that result is disallowed. That is, on sequentially consistent hardware, the answer to the litmus test—can this program see r1 = 1, r2 = 0?—is no.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;由于没有任何交织结果是以 r1 = 1，r2 = 0 结束的，因此该结果是不允许的。也就是说，在顺序一致的硬件上，试金石测试的答案是否定的--这个程序能否看到 r1 = 1，r2 = 0？&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;A good mental model for sequential consistency is to imagine all the processors connected directly to the same shared memory, which can serve a read or write request from one thread at a time. There are no caches involved, so every time a processor needs to read from or write to memory, that request goes to the shared memory. The single-use-at-a-time shared memory imposes a sequential order on the execution of all the memory accesses: sequential consistency.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;顺序一致性的一个很好的思维模型是想象所有处理器直接连接到同一个共享内存，该共享内存可以同时满足一个线程的读取或写入请求。这里不涉及缓存，因此每次处理器需要读取或写入内存时，请求都会进入共享内存。一次性使用的共享内存对所有内存访问的执行都规定了顺序：顺序一致性。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%204.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This diagram is a model for a sequentially consistent machine, not the only way to build one. Indeed, it is possible to build a sequentially consistent machine using multiple shared memory modules and caches to help predict the result of memory fetches, but being sequentially consistent means that machine must be-have indistinguishably from this model. If we are simply trying to understand what sequentially consistent execution means, we can ignore all of those possible implementation complications and think about this one model.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;本图是顺序一致机器的模型，而不是构建顺序一致机器的唯一方法。事实上，我们可以利用多个共享内存模块和缓存来帮助预测内存获取的结果，从而构建一个顺序一致的机器，但顺序一致意味着该机器必须与此模型无异。如果我们只是想了解顺序一致执行的含义，我们可以忽略所有这些可能的实现复杂性，只考虑这一个模型。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Unfortunately for us as programmers, giving up strict sequential consistency can let hardware execute programs faster, so all modern hardware deviates in various ways from sequential consistency. Deﬁning exactly how speciﬁc hardware deviates turns out to be quite diﬃcult. This post uses as two examples two memory models present in today’s widely-used hardware: that of the x86, and that of the ARM and POWER processor families.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;不幸的是，对于我们程序员来说，放弃严格的顺序一致性可以让硬件更快地执行程序，因此所有现代硬件都以各种方式偏离顺序一致性。要准确判断特定硬件是如何偏离顺序一致性的，是一件相当困难的事情。本文章以当今广泛使用的硬件中的两种内存模型为例：x86 以及 ARM 和 POWER 处理器系列。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;x86-total-store-order-x86-tso&quot;&gt;x86 Total Store Order (x86-TSO)&lt;a class=&quot;zola-anchor&quot; href=&quot;#x86-total-store-order-x86-tso&quot; aria-label=&quot;Anchor link for: x86-total-store-order-x86-tso&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;blockquote&gt;
&lt;p&gt;The memory model for modern x86 systems corresponds to this hardware diagram:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;现代 x86 系统的内存模型与此硬件图相对应：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%205.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;All the processors are still connected to a single shared memory, but each processor queues writes to that memory in a local write queue. The processor continues executing new instructions while the writes make their way out to the shared memory. A memory read on one processor consults the local write queue before consulting main memory, but it cannot see the write queues on other processors. The eﬀect is that a processor sees its own writes before others do. But—and this is very important—all processors do agree on the (total) order in which writes (stores) reach the shared memory, giving the model its name: total store order, or TSO. At the moment that a write reaches shared memory, any future read on any processor will see it and use that value (until it is overwritten by a later write, or perhaps by a buﬀered write from another processor).&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;所有处理器仍连接到单个共享内存，但每个处理器都在本地写入队列中排队写入该内存。处理器在写入共享内存的同时继续执行新指令。一个处理器读取内存时，会先查询本地写入队列，然后再查询主内存，但它看不到其他处理器上的写入队列。这样做的后果是，处理器会比其他处理器先看到自己的写入。但是--这一点非常重要--所有处理器都同意写入（存储）到达共享内存的（总）顺序，因此该模型被命名为：总存储顺序，或 TSO。在写入到达共享内存的那一刻，任何处理器上未来的读取都会看到并使用该值（直到该值被后来的写入覆盖，或者被其他处理器建立的写入覆盖）。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The write queue is a standard ﬁrst-in, ﬁrst-out queue: the memory writes are applied to the shared memory in the same order that they were executed by the processor. Because the write order is preserved by the write queue, and because other processors see the writes to shared memory immediately, the message passing litmus test we considered earlier has the same outcome as before: r1 = 1, r2 = 0 remains impossible.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;写入队列是一个标准的先进先出队列：内存写入的顺序与处理器执行的顺序相同。由于写入队列保留了写入顺序，而且其他处理器会立即看到写入共享内存的内容，因此我们之前考虑过的消息传递试金石测试结果与之前相同：r1 = 1，r2 = 0 仍然是不可能的。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%206.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The write queue guarantees that thread 1 writes x to memory before y, and the system-wide agreement about the order of memory writes (the total store order) guarantees that thread 2 learns of x’s new value before it learns of y’s new value. Therefore it is impossible for r1 = y to see the new y without r2 = x also seeing the new x. The store order is crucial here: thread 1 writes x before y, so thread 2 must not see the write to y before the write to x.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;写入队列保证线程 1 在写入 y 之前将 x 写入内存，而全系统对内存写入顺序（总存储顺序）的约定则保证线程 1 在写入 y 之前将 x 写入内存。全系统对内存写入顺序（总存储顺序）的一致保证了线程 2 在得知 y 的新值之前，先得知 x 的新值。因此，如果没有 r2 = x 也看到新的 x，r1 = y 就不可能看到新的 y。存储顺序在这里至关重要：线程 1 在写入 y 之前写入 x，因此线程 2 在写入 x 之前一定看不到写入 y 的内容。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The sequential consistency and TSO models agree in this case, but they disagree about the results of other litmus tests. For example, this is the usual example distinguishing the two models:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;在这种情况下，顺序一致性模型和 TSO 模型是一致的，但它们在其他试金石测试的结果上存在分歧。例如，这是区分两种模型的常见例子：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%207.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In any sequentially consistent execution, either x = 1 or y = 1 must happen ﬁrst, and then the read in the other thread must observe it, so r1 = 0, r2 = 0 is impossible. But on a TSO system, it can happen that Thread 1 and Thread 2 both queue their writes and then read from memory before either write makes it to memory, so that both reads see zeros.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;在任何顺序一致的执行中，x = 1 或 y = 1 必须首先发生，然后另一个线程的读取必须观察到它，因此 r1 = 0, r2 = 0 是不可能的。但在 TSO 系统中，线程 1 和线程 2 都会排队等待写入，然后在任何一个写入到达内存之前从内存中读取，这样两个读取都会看到零。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This example may seem artiﬁcial, but using two synchronization variables does happen in well-known synchronization algorithms, such as Dekker’s algorithm or Peterson’s algorithm, as well as ad hoc schemes. They break if one thread isn’t seeing all the writes from another.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;这个例子看似很特别，但在德克算法或彼得森算法等著名同步算法以及特别方案中，使用两个同步变量的情况确实存在。如果一个线程没有看到另一个线程的所有写入，它们就会崩溃。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;To ﬁx algorithms that depend on stronger memory ordering, non-sequentially-consistent hardware supplies explicit instructions called memory barriers (or fences) that can be used to control the ordering. We can add a memory barrier to make sure that each thread ﬂushes its previous write to memory before starting its read:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;为了优化依赖于更强内存排序的算法，非顺序一致性硬件提供了称为内存屏障（或栅栏）的显式指令，可用于控制排序。我们可以添加内存栅栏，确保每个线程在开始读取之前，先清除之前写入内存的内容：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%208.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;With the addition of the barriers, r1 = 0, r2 = 0 is again impossible, and Dekker’s or Peterson’s algorithm would then work correctly. There are many kinds of barriers; the details vary from system to system and are beyond the scope of this post. The point is only that barriers exist and give programmers or language implementers a way to force sequentially consistent behavior at critical moments in a program.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;增加障碍后，r1 = 0、r2 = 0 又是不可能的，这样德克或彼得森的算法就能正确运行了。障碍有很多种，具体情况因系统而异，不在本文讨论范围之内。问题的关键在于，障碍的存在为程序员或语言实现者提供了一种在程序关键时刻强制执行顺序一致行为的方法。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;One ﬁnal example, to drive home why the model is called total store order. In the model, there are local write queues but no caches on the read path. Once a write reaches main memory, all processors not only agree that the value is there but also agree about when it arrived relative to writes from other processors. Consider this litmus test:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;举一个例子来说明为什么这个模型被称为 &quot; total store order&quot;。在该模型中，有本地写入队列，但读取路径上没有缓存。一旦写入内容到达主内存，所有处理器不仅会一致同意该值存在，还会一致同意该值相对于其他处理器写入内容的到达时间。考虑一下这个试金石：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%209.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;If Thread 3 sees x change before y, can Thread 4 see y change before x? For x86 and other TSO machines, the answer is no: there is a total order over all stores (writes) to main memory, and all processors agree on that order, subject to the wrinkle that each processor knows about its own writes before they reach main memory.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;如果线程 3 在 y 之前看到 x 的变化，那么线程 4 能否在 x 之前看到 y 的变化？对于 x86 和其他 TSO 机器，答案是否定的：所有存储（写入）到主内存的操作都有一个总的顺序，所有处理器都同意这个顺序，但有一个小问题，即每个处理器在写入到主内存之前都知道自己的写入操作。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;the-path-to-x86-tso&quot;&gt;The Path to x86-TSO&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-path-to-x86-tso&quot; aria-label=&quot;Anchor link for: the-path-to-x86-tso&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;blockquote&gt;
&lt;p&gt;The x86-TSO model seems fairly clean, but the path there was full of roadblocks and wrong turns. In the 1990s, the manuals available for the ﬁrst x86 multiprocessors said next to nothing about the memory model provided by the hardware.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;x86-TSO 模型看起来相当简洁，但在实现这一目标的道路上却充满了障碍和弯路。20 世纪 90 年代，第一代 x86 多核处理器的使用手册几乎没有提及硬件提供的内存模型。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;As one example of the problems, Plan 9 was one of the ﬁrst true multiprocessor operating systems (without a global kernel lock) to run on the x86. During the port to the multiprocessor Pentium Pro, in 1997, the developers stumbled over unexpected behavior that boiled down to the write queue litmus test. A subtle piece of synchronization code assumed that r1 = 0, r2 = 0 was impossible, and yet it was happening. Worse, the Intel manuals were vague about the memory model details.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Plan 9 是第一个在 x86 处理器上运行的真正的多处理器操作系统（没有全局内核锁），这就是问题的一个例子。1997 年，在移植到多处理器 Pentium Pro 的过程中，开发人员偶然发现了一些意想不到的行为，这些行为可以归结为写入队列试金石测试。一段微妙的同步代码假定 r1 = 0，r2 = 0 是不可能的，但却发生了。更糟糕的是，英特尔手册对内存模型的细节含糊其辞。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In response to a mailing list suggestion that “it’s better to be conservative with locks than to trust hardware designers to do what we expect,” one of the Plan 9 developers explained the problem well:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;针对邮件列表中有人提出的 &quot;与其相信硬件设计人员会按我们的期望行事，不如对锁采取保守的态度 &quot;的建议，Plan 9 的一位开发人员很好地解释了这个问题：&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I certainly agree. We are going to encounter more relaxed ordering in multiprocessors. The question is, what do the hardware designers consider conservative? Forcing an interlock at both the beginning and end of a locked section seems to be pretty conservative to me, but I clearly am not imaginative enough. The Pro manuals go into excruciating detail in describing the caches and what keeps them coherent but don’t seem to care to say anything detailed about execution or read ordering. The truth is that we have no way of knowing whether we’re conservative enough.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;我当然同意。我们将在多处理器中遇到更宽松的排序。问题是，硬件设计人员认为什么是保守的？在锁定部分的开头和结尾强制联锁在我看来是相当保守的，但我显然没有足够的想象力。专业手册详细描述了缓存和保持缓存一致性的方法，但似乎并不关心执行或读取顺序的细节。事实上，我们根本无法知道自己是否足够保守。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;During the discussion, an architect at Intel gave an informal explanation of the memory model, pointing out that in theory even multiprocessor 486 and Pentium systems could have produced the r1 = 0, r2 = 0 result, and that the Pentium Pro simply had larger pipelines and write queues that exposed the behavior more often.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;在讨论过程中，英特尔公司的一位架构师对内存模型作了非正式的解释，他指出，从理论上讲，即使是多处理器 486 和奔腾系统也可能产生 r1 = 0、r2 = 0 的结果，奔腾 Pro 只是拥有更大的流水线和写入队列，从而更频繁地暴露出这种行为。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Intel architect also wrote:Loosely speaking, this means the ordering of events originating from any one processor in the system, as observed by other processors, is always the same. However, diﬀerent observers are allowed to disagree on the interleaving of events from two or more processors. Future Intel processors will implement the same memory ordering model.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;英特尔架构师还写道：
从广义上讲，这意味着其他处理器观察到的来自系统中任何一个处理器的事件的排序总是相同的。但是，不同的观察者可以对来自两个或多个处理器的事件的交错顺序产生分歧。未来的英特尔处理器将采用相同的内存排序模型。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The claim that “diﬀerent observers are allowed to disagree on the interleaving of events from two or more processors” is saying that the answer to the IRIW litmus test can answer “yes” on x86, even though in the previous section we saw that x86 answers “no.” How can that be?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;所谓 &quot;允许不同的观察者对来自两个或多个处理器的事件交错存在不同意见&quot;，就是说，IRIW试金石的答案在 x86 上可以是 &quot;是&quot;，尽管在上一节中我们看到 x86 的答案是 &quot;否&quot;。这怎么可能呢？&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The answer appears to be that Intel processors never actually answered “yes” to that litmus test, but at the time the Intel architects were reluctant to make any guarantee for future processors. What little text existed in the architecture manuals made almost no guarantees at all, making it very diﬃcult to program against.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;答案似乎是，英特尔处理器实际上从未对这一试金石作出 &quot;是 &quot;的回答，但当时的英特尔架构师不愿对未来的处理器作出任何保证。架构手册中仅有的一点文字几乎没有做出任何保证，这使得针对处理器进行编程变得非常困难。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The Plan 9 discussion was not an isolated event. The Linux kernel developers spent over a hundred messages on their mailing list starting in late November 1999 in similar confusion over the guarantees provided by Intel processors.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Plan 9 的讨论并非孤立事件。从 1999 年 11 月底开始，Linux 内核开发人员在他们的邮件列表上花费了一百多条信息，对英特尔处理器提供的保证进行了类似的混乱讨论。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In response to more and more people running into these diﬃculties over the decade that followed, a group of architects at Intel took on the task of writing down useful guarantees about processor behavior, for both current and future processors. The ﬁrst result was the “Intel 64 Architecture Memory Ordering White Paper”, published in August 2007, which aimed to “provide software writers with a clear understanding of the results that diﬀerent sequences of memory access instructions may produce.” AMD published a similar description later that year in the AMD64 Architecture Programmer’s Manual revision 3.14. These descriptions were based on a model called “total lock order + causal consistency” (TLO+CC), intentionally weaker than TSO. In public talks, the Intel architects said that TLO+CC was “as strong as required but no stronger.” In particular, the model reserved the right for x86 processors to answer “yes” to the IRIW litmus test. Unfortunately, the deﬁnition of the memory barrier was not strong enough to reestablish sequentially-consistent memory semantics, even with a barrier after every instruction. Even worse, researchers observed actual Intel x86 hardware violating the TLO+CC model. For example:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;在随后的十年中，越来越多的人遇到了这些问题，英特尔公司的一群架构师开始着手为当前和未来的处理器编写有关处理器行为的有用保证。第一个成果是 2007 年 8 月发布的 &quot;英特尔 64 架构内存排序白皮书&quot;，旨在 &quot;让软件编写人员清楚地了解不同的内存访问指令序列可能产生的结果&quot;。同年晚些时候，AMD 在《AMD64 架构程序员手册》3.14 修订版中也发布了类似的说明。这些描述基于一种称为 &quot;总锁定顺序+因果一致性&quot;（TLO+CC）的模型，有意弱化了 TSO。在公开演讲中，英特尔架构师表示 TLO+CC 是 &quot;所需的强度，但没有更强&quot;。特别是，该模型为 x86 处理器保留了在 IRIW 试金石测试中回答 &quot;是 &quot;的权利。遗憾的是，即使在每条指令之后都设置了障碍，内存障碍的定义也不足以重新建立顺序一致的内存语义。更糟糕的是，研究人员观察到实际的英特尔 x86 硬件违反了 TLO+CC 模型。例如&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2010.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Revisions to the Intel and AMD speciﬁcations later in 2008 guaranteed a “no” to the IRIW case and strengthened the memory barriers but still permitted unexpected behaviors that seem like they could not arise on any reasonable hardware. For example:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;2008 年晚些时候，英特尔和 AMD 对规范进行了修订，保证了 IRIW 情况下的 &quot;否&quot;，并加强了内存障碍，但仍允许出现意外行为，这些行为似乎不可能在任何合理的硬件上出现。例如&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2011.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;To address these problems, Owens et al. proposed the x86-TSO model, based on the earlier SPARCv8 TSO model. At the time they claimed that “To the best of our knowledge, x86-TSO is sound, is strong enough to program above, and is broadly in line with the vendors’ intentions.” A few months later Intel and AMD released new manuals broadly adopting this model.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;为了解决这些问题，Owens 等人在早期 SPARCv8 TSO 模型的基础上提出了 x86-TSO 模型。当时他们声称：&quot;据我们所知，x86-TSO 是合理的，足以在上面进行编程，而且与供应商的意图基本一致。几个月后，英特尔和 AMD 发布了新的手册，广泛采用了这一模型。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;It appears that all Intel processors did implement x86-TSO from the start, even though it took a decade for Intel to decide to commit to that. In retrospect, it is clear that the Intel and AMD architects were struggling with exactly how to write a memory model that left room for future processor optimizations while still making useful guarantees for compiler writers and assembly-language programmers. “As strong as required but no stronger” is a diﬃcult balancing act.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;尽管英特尔花了十年时间才决定采用 x86-TSO，但似乎所有英特尔处理器从一开始就采用了 x86-TSO。现在回过头来看，英特尔和 AMD 的架构师们显然都在苦苦思索，到底该如何编写一个内存模型，既能为未来的处理器优化留有余地，又能为编译器编写者和汇编语言程序员提供有用的保证。&quot;强如所需，但不能更强 &quot;是一种艰难的平衡行为。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;arm-power-relaxed-memory-model&quot;&gt;ARM&#x2F;POWER Relaxed Memory Model&lt;a class=&quot;zola-anchor&quot; href=&quot;#arm-power-relaxed-memory-model&quot; aria-label=&quot;Anchor link for: arm-power-relaxed-memory-model&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Now let’s look at an even more relaxed memory model, the one found on ARM and POWER processors. At an implementation level, these two systems are diﬀerent in many ways, but the guaranteed memory consistency model turns out to be roughly similar, and quite a bit weaker than x86-TSO or even x86-TLO+CC.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;现在，让我们来看看更宽松的内存模型，即 ARM 和 POWER 处理器上的内存模型。ARM 和 POWER 处理器上的内存模型。在实现层面上，这两个系统 在实现层面上，这两个系统在很多方面都有所不同，但保证内存一致性的模型 大致相似，而且比 x86-TSO 甚至 x86-TLO+CC 要弱得多。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The conceptual model for ARM and POWER systems is that each processor reads from and writes to its own complete copy of memory, and each write propagates to the other processors independently, with reordering allowed as the writes propagate.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;ARM 和 POWER 系统的概念模型是，每个处理器从自己的完整内存副本读取数据并写入，每个写入都会独立传播到其他处理器，在写入传播过程中允许重新排序。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2012.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here, there is no total store order. Not depicted, each processor is also allowed to postpone a read until it needs the result: a read can be delayed until after a later write. In this relaxed model, the answer to every litmus test we’ve seen so far is “yes, that really can happen.”&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;这里没有总存储顺序。如图所示，每个处理器还可以推迟读取，直到需要结果为止：读取可以延迟到稍后的写入之后。在这个宽松的模型中，我们迄今为止看到的所有试金石的答案都是&quot;是的，这种情况确实可能发生&quot;。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;For the original message passing litmus test, the reordering of writes by a single processor means that Thread 1’s writes may not be observed by other threads in the same order:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;对于最初的消息传递试金石测试来说，单个处理器对写入内容的重新排序意味着线程 1 的写入内容可能不会被其他线程以相同的顺序观测到：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2013.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;In the ARM&#x2F;POWER model, we can think of thread 1 and thread 2 each having their own separate copy of memory, with writes propagating between the memories in any order whatsoever. If thread 1’s memory sends the update of y to thread 2 before sending the update of x, and if thread 2 executes between those two updates, it will indeed see the result r1 = 1, r2 = 0.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;在 ARM&#x2F;POWER 模型中，我们可以认为线程 1 和线程 2 各自拥有独立的内存副本，写入可以以任何顺序在内存之间传播。如果线程 1 的内存先向线程 2 发送 y 的更新，然后再发送 x 的更新，如果线程 2 在这两个更新之间执行，那么它确实会看到 r1 = 1、r2 = 0 的结果。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This result shows that the ARM&#x2F;POWER memory model is weaker than TSO: it makes fewer requirements on the hardware. The ARM&#x2F;POWER model still admits the kinds of reorderings that TSO does:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;这一结果表明，ARM&#x2F;POWER 内存模型比 TSO 弱： 它对硬件的要求更低。ARM&#x2F;POWER 模型仍然进行 TSO 所允许的重新排序：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2014.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;On ARM&#x2F;POWER, the writes to x and y might be made to the local memories but not yet have propagated when the reads occur on the opposite threads.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;在 ARM&#x2F;POWER 上，对 x 和 y 的写入可能已经写入本地内存 但当读取发生在相反的线程上时，写入还未传播。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here’s the litmus test that showed what it meant for x86 to have a total store order:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;以下是显示 x86 拥有总存储的意义的试金石 顺序：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2015.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;On ARM&#x2F;POWER, diﬀerent threads may learn about diﬀerent writes in diﬀerent orders. They are not guaranteed to agree about a total order of writes reaching main memory, so Thread 3 can see x change before y while Thread 4 sees y change before x.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;在 ARM&#x2F;POWER 上，不同的线程可能以不同的顺序了解不同的写入。它们不能保证在写入主内存的总顺序上达成一致，因此线程 3 可能会在 y 之前看到 x 的变化，而线程 4 则会在 x 之前看到 y 的变化。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;As another example, ARM&#x2F;POWER systems have visible buﬀering or reordering of memory reads (loads), as demonstrated by this litmus test:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;另一个例子是，ARM&#x2F;POWER 系统在内存读取（加载）过程中会出现明显的分层或重新排序，这个试金石测试就证明了这一点：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2016.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Any sequentially consistent interleaving must start with either thread 1’s r1 = x or thread 2’s r2 = y. That read must see a zero, making the outcome r1 = 1, r2 = 1 impossible. In the ARM&#x2F;POWER memory model, however, processors are allowed to delay reads until after writes later in the instruction stream, so that y = 1 and x = 1 execute before the two reads.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;任何顺序一致的交错都必须从线程 1 的 r1 = x 或线程 2 的 r2 = y 开始。不过，在 ARM&#x2F;POWER 内存模型中，允许处理器将读取延迟到指令流后面的写入之后，这样 y = 1 和 x = 1 就会在两个读取之前执行。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Although both the ARM and POWER memory models allow this result, Maranget et al. reported (in 2012) being able to reproduce it empirically only on ARM systems, never on POWER. Here the divergence between model and reality comes into play just as it did when we examined Intel x86: hardware implementing a stronger model than technically guaranteed encourages dependence on the stronger behavior and means that future, weaker hardware will break programs, validly or not.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;虽然 ARM 和 POWER 内存模型都允许出现这一结果，但 Maranget 等人（2012 年）报告说，他们只能在 ARM 系统上根据经验重现这一结果，而从未在 POWER 系统上重现过。在这里，模型与现实之间的差异就像我们研究英特尔 x86 系统时一样发挥作用：实施比技术上保证的更强模型的硬件会鼓励对更强行为的依赖，并意味着未来可能出现的更强行为。对较强行为的依赖，这意味着未来较弱的硬件会破坏程序，无论是否有效。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Like on TSO systems, ARM and POWER have barriers that we can insert into the examples above to force sequentially consistent behaviors. But the obvious question is whether ARM&#x2F;POWER without barriers excludes any behavior at all. Can the answer to any litmus test ever be “no, that can’t happen?” It can, when we focus on a single memory location.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;与 TSO 系统一样，ARM 和 POWER 也有障碍，我们可以在上述示例中插入这些障碍，以强制实现顺序一致的行为。但显而易见的问题是，没有障碍的 ARM&#x2F;POWER 是否会排除任何行为。任何试金石测试的答案都可能是 &quot;不，这不可能发生? &quot;。当我们专注于单个内存位置时，答案是肯定的。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2017.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;This litmus test is like the previous one, but now both threads are writing to a single variable x instead of two distinct variables x and y. Threads 1 and 2 write conﬂicting values 1 and 2 to x, while Thread 3 and Thread 4 both read x twice. If Thread 3 sees x = 1 overwritten by x = 2, can Thread 4 see the opposite?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;线程 1 和 2 向 x 写入相互矛盾的值 1 和 2，而线程 3 和线程 4 都读取 x 两次。
如果线程 3 看到 x = 1 被 x = 2 覆盖，那么线程 4 能否看到相反的情况？&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The answer is no, even on ARM&#x2F;POWER: threads in the system must agree about a total order for the writes to a single memory location. That is, threads must agree which writes overwrite other writes. This property is called called coherence. Without the coherence property, processors either disagree about the ﬁnal result of memory or else report a memory location ﬂip-ﬂopping from one value to another and back to the ﬁrst. It would be very diﬃcult to program such a system.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;答案是否定的，即使在 ARM&#x2F;POWER 上也是如此：系统中的线程必须就写入单个内存位置的总顺序达成一致。也就是说，线程必须就哪些写入覆盖其他写入达成一致。这一特性被称为一致性。如果没有一致性，处理器要么会对内存的最终结果产生分歧，要么会报告内存位置从一个值跳转到另一个值，然后又回到第一个值。对这样的系统进行编程是非常困难的。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’m purposely leaving out a lot of subtleties in the ARM and POWER weak memory models. For more detail, see any of Peter Sewell’s papers on the topic. Also, ARMv8 strengthened the memory model by making it “multicopy atomic,” but I won’t take the space here to explain exactly what that means.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;我特意忽略了 ARM 和 POWER 弱内存模型中的许多微妙之处。如需了解更多细节，请参阅 Peter Sewell 有关该主题的任何论文。此外，ARMv8 通过使其成为 &quot;多拷贝原子 &quot;来加强内存模型，但我不会在这里花篇幅解释这到底意味着什么。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are two important points to take away. First, there is an incredible amount of subtlety here, the subject of well over a decade of academic research by very persistent, very smart people. I don’t claim to understand anywhere near all of it myself. This is not something we should hope to explain to ordinary programmers, not something that we can hope to keep straight while debugging ordinary programs. Second, the gap between what is allowed and what is observed makes for unfortunate future surprises. If current hardware does not exhibit the full range of allowed behaviors—especially when it is diﬃcult to reason about what is allowed in the ﬁrst place!—then inevitably programs will be written that accidentally depend on the more restricted behaviors of the actual hardware. If a new chip is less restricted in its behaviors, the fact that the new behavior breaking your program is technically allowed by the hardware memory model—that is, the bug is technically your fault—is of little consolation. This is no way to write programs.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;有两点很重要。首先，这里有令人难以置信的微妙之处，是非常执着、非常聪明的人十多年学术研究的主题。我并不声称自己理解了其中的全部内容。这不是我们应该希望向普通程序员解释的东西，也不是我们可以希望在调试普通程序时保持正确的东西。其次，允许使用的功能与观察到的功能之间的差距会给未来带来不幸的意外。如果当前的硬件没有展示出全部允许的行为--尤其是当推理什么是允许的行为非常困难的时候！那么不可避免的是，编写的程序会意外地依赖于实际硬件中限制较多的行为。如果新芯片的行为限制较少，那么尽管硬件内存模型在技术上允许破坏程序的新行为--也就是说，从技术上讲，错误是你的过失--但这并不能起到什么安慰作用。这不是编写程序的方式。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;weak-ordering-and-data-race-free-sequential-consistency&quot;&gt;Weak Ordering and Data-Race-Free Sequential Consistency&lt;a class=&quot;zola-anchor&quot; href=&quot;#weak-ordering-and-data-race-free-sequential-consistency&quot; aria-label=&quot;Anchor link for: weak-ordering-and-data-race-free-sequential-consistency&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;blockquote&gt;
&lt;p&gt;By now I hope you’re convinced that the hardware details are complex and subtle and not something you want to work through every time you write a program. Instead, it would help to identify shortcuts of the form “if you follow these easy rules, your program will only produce results as if by some sequentially consistent interleaving.” (We’re still talking about hardware, so we’re still talking about interleaving individual assembly instructions.)&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;现在，我希望你已经相信，硬件细节是复杂而微妙的，并不是你每次编写程序时都想解决的问题。相反，找出 &quot;如果你遵循这些简单的规则，你的程序就会像通过某种顺序一致的交织一样产生结果 &quot;这种形式的捷径会有所帮助。(我们仍在讨论硬件，所以我们仍在讨论交错单个汇编指令）。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sarita Adve and Mark Hill proposed exactly this approach in their 1990 paper “Weak Ordering – A New Deﬁnition”. They deﬁned “weakly ordered” as follows.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;萨里塔-阿德维和马克-希尔在 1990 年发表的论文《弱排序--一个新定义》中提出的正是这种方法。他们将 &quot;弱排序 &quot;定义如下。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let a synchronization model be a set of constraints on memory accesses that specify how and when synchronization needs to be done. Hardware is weakly ordered with respect to a synchronization model if and only if it appears sequentially consistent to all software that obey the synchronization model.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;让同步模型成为一组内存访问的约束条件，这些约束条件规定了同步的方式和时间。当且仅当硬件与所有遵守同步模型的软件在顺序上一致时，硬件在同步模型方面才是弱有序的。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Although their paper was about capturing the hardware designs of that time (not x86, ARM, and POWER), the idea of elevating the discussion above specific designs, keeps the paper relevant today.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;虽然他们的论文是关于捕捉当时的硬件设计（而不是 x86、ARM 和 POWER），但将讨论提升到特定设计之上的想法，使这篇论文至今仍具有现实意义。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I said before that “valid optimizations do not change the behavior of valid programs.” The rules deﬁne what valid means, and then any hardware optimizations have to keep those programs working as they might on a sequentially consistent machine. Of course, the interesting details are the rules themselves, the constraints that deﬁne what it means for a program to be valid.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;我之前说过，&quot;有效的优化不会改变有效程序的行为&quot;。规则定义了有效的含义，然后任何硬件优化都必须保持这些程序在顺序一致的机器上正常运行。当然，有趣的细节在于规则本身，即确定程序有效含义的约束条件。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Adve and Hill propose one synchronization model, which they call data-race-free (DRF). This model assumes that hardware has memory synchronization operations separate from ordinary memory reads and writes. Ordinary memory reads and writes may be reordered between synchronization operations, but they may not be moved across them. (That is, the synchronization operations also serve as barriers to reordering.) A program is said to be data-race-free if, for all idealized sequentially consistent executions, any two ordinary memory accesses to the same location from diﬀerent threads are either both reads or else separated by synchronization operations forcing one to happen before the other.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Adve 和 Hill 提出了一种同步模型，他们称之为无数据链路 (DRF)。该模型假设硬件的内存同步操作与普通内存读写操作是分开的。普通内存读写可以在同步操作之间重新排序，但不能在同步操作之间移动。(也就是说，同步操作也是重新排序的障碍）。如果在所有理想化的顺序一致的执行过程中，来自不同线程对同一位置的任意两次普通内存访问要么都是读取，要么都被同步操作隔开，迫使其中一次先于另一次发生，那么这个程序就被称为无数据竞赛程序。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let’s look at some examples, taken from Adve and Hill’s paper (redrawn for presentation). Here is a single thread that executes a write of variable x followed by a read of the same variable.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;让我们来看看 Adve 和 Hill 论文中的一些例子（为便于演示而重新绘制）。重绘）。下面是一个单线程，它在执行写入变量 x 之后 然后读取同一变量。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2018.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;The vertical arrow marks the order of execution within a single thread: the write happens, then the read. There is no race in this program, since everything is in a single thread.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;垂直箭头表示单个线程的执行顺序：先写入，然后读取。在这个程序中不存在竞赛，因为一切都在单线程中进行。单线程中。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2019.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Here, thread 2 writes to x without coordinating with thread 1. Thread 2’s write races with both the write and the read by thread 1. If thread 2 were reading x instead of writing it, the program would have only one race, between the write in thread 1 and the read in thread 2. Every race involves at least one write: two uncoordinated reads do not race with each other.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;在这里，线程 2 在不与线程 1 协调的情况下写入 x。线程 2 的写 与线程 1 的写和读发生竞赛。如果线程 2 读取 x 而不是写入 x，程序将只有一次竞赛，即线程 1 的写入和线程 2 的读取之间的竞赛。线程 1 的写和线程 2 的读之间。每一次竞赛都至少涉及一次写入：两次不协调的读取不会发生竞赛。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;To avoid races, we must add synchronization operations, which force an order between operations on diﬀerent threads sharing a synchronization variable. If the synchronization S(a) (synchronizing on variable a, marked by the dashed arrow) forces thread 2’s write to happen after thread 1 is done, the race is eliminated:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;为了避免竞赛，我们必须添加同步操作，强制共享同步变量的不同线程之间的操作顺序。如果同步 S(a)（同步变量 a，用虚线箭头标记）强制线程 2 在线程 1 完成后写入，竞赛就会消除：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2020.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now the write by thread 2 cannot happen at the same time as thread 1’s operations.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;现在，线程 2 的写操作不能与线程 1 的操作同时进行。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;If thread 2 were only reading, we would only need to synchronize with thread 1’s write. The two reads can still proceed concurrently:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;如果线程 2 只读取数据，我们只需与线程 1 的写同步即可。两个读取仍然可以同时进行：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2021.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Threads can be ordered by a sequence of synchronizations, even using an intermediate thread. This program has no race:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;线程可以通过同步序列排序，甚至可以使用中间线程。这个程序没有竞赛：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2022.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;On the other hand, the use of synchronization variables does not by itself eliminate races: it is possible to use them incorrectly. This program does have a race:&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;另一方面，使用同步变量本身并不能消除竞赛：错误使用同步变量也是有可能的。这个程序确实存在竞赛：&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;img&#x2F;hardwarememorymodel1&#x2F;Untitled%2023.png&quot; alt=&quot;Untitled&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thread 2’s read is properly synchronized with the writes in the other threads—it deﬁnitely happens after both—but the two writes are not themselves synchronized. This program is not data-race-free.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;线程 2 的读取与其他线程的写入是同步的--它绝对发生在两个线程之后。但两个写操作本身并不同步。这个程序并非无数据竞赛。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Adve and Hill presented weak ordering as “a contract between software and hardware,” speciﬁcally that if software avoids data races, then hardware acts as if it is sequentially consistent, which is easier to reason about than the models we were examining in the earlier sections. But how can hardware satisfy its end of the contract?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Adve 和 Hill 将弱排序说成是 &quot;软件和硬件之间的契约&quot;，具体来说，如果软件避免了数据竞赛，那么硬件的行为就好像是顺序一致的，这比我们在前面章节中研究的模型更容易推理。但是，硬件如何才能履行其合约呢？&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Adve and Hill gave a proof that hardware “is weakly ordered by DRF,” meaning it executes data-race-free programs as if by a sequentially consistent ordering, provided it meets a set of certain minimum requirements. I’m not going to go through the details, but the point is that after the Adve and Hill paper, hardware designers had a cookbook recipe backed by a proof: do these things, and you can assert that your hardware will appear sequentially consistent to data-race-free programs. And in fact, most relaxed hardware did behave this way and has continued to do so, assuming appropriate implementations of the synchronization operations. Adve and Hill were concerned originally with the VAX, but certainly x86, ARM, and POWER can satisfy these constraints too. This idea that a system guarantees to data-race-free programs the appearance of sequential consistency is often abbreviated DRF-SC.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Adve 和 Hill 证明了硬件 &quot;通过 DRF 弱排序&quot;，也就是说，只要满足一组特定的最低要求，硬件就能像通过顺序一致的排序一样执行无数据竞赛程序。我不想细说，但重点是，在 Adve 和 Hill 的论文发表后，硬件设计者就有了一份有证明支持的食谱：只要做到这些，你就可以断言，你的硬件在执行无数据竞序程序时会表现出顺序一致性。而事实上，只要同步操作实现得当，大多数宽松的硬件确实是这样表现的，而且一直如此。Adve 和 Hill 最初关注的是 VAX，但 x86、ARM 和 POWER 当然也能满足这些约束。系统保证无数据race程序的外观顺序一致性，这一观点通常被缩写为 DRF-SC。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;DRF-SC marked a turning point in hardware memory models, providing a clear strategy for both hardware designers and software authors, at least those writing software in assembly language. As we will see in the next post, the question of a memory model for a higher-level programming language does not have as neat and tidy an answer.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;DRF-SC 标志着硬件内存模型的转折点，为硬件设计者和软件作者（至少是那些用汇编语言编写软件的作者）提供了明确的策略。我们将在下一篇文章中看到，高级编程语言的内存模型问题并没有那么整齐划一。&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>C | 获取当前GCC版本</title>
          <pubDate>Sun, 10 Mar 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-03-10-c-get-gcc-version/</link>
          <guid>https://inasa.dev/posts/24-03-10-c-get-gcc-version/</guid>
          <description xml:base="https://inasa.dev/posts/24-03-10-c-get-gcc-version/">&lt;p&gt;&lt;code&gt;__GNUC__&lt;&#x2F;code&gt;,&lt;code&gt;__GNUC_MINOR__&lt;&#x2F;code&gt;和&lt;code&gt;__GNUC_PATCHLEVEL__&lt;&#x2F;code&gt;宏是当前系统的&lt;code&gt;gcc&lt;&#x2F;code&gt;版本。这些宏分别定义了&lt;code&gt;gcc&lt;&#x2F;code&gt;的主版本号、次版本号和补丁版本号。
这些宏定义在&lt;code&gt;&amp;lt;features.h&amp;gt;&lt;&#x2F;code&gt;头文件中。&lt;&#x2F;p&gt;
&lt;p&gt;如果&lt;code&gt;__GNUC__&lt;&#x2F;code&gt;的值为7，&lt;code&gt;__GNUC_MINOR__&lt;&#x2F;code&gt;的值为2，&lt;code&gt;__GNUC_PATCHLEVEL__&lt;&#x2F;code&gt;的值为0，那么当前系统的&lt;code&gt;gcc&lt;&#x2F;code&gt;版本为7.2.0。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-include z-c&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-include z-c&quot;&gt;#include&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-other z-lt-gt z-include z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;stdio.h&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-preprocessor z-include z-c&quot;&gt;&lt;span class=&quot;z-keyword z-control z-import z-include z-c&quot;&gt;#include&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-other z-lt-gt z-include z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;features.h&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;gcc major version: &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; __GNUC__&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;gcc minor version: &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; __GNUC_MINOR__&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;  &lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-support z-function z-C99 z-c&quot;&gt;printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;gcc patch level: &lt;span class=&quot;z-constant z-other z-placeholder z-c&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-c&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-c&quot;&gt;,&lt;&#x2F;span&gt; __GNUC_PATCHLEVEL__&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;  &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</description>
      </item>
      <item>
          <title>Go | 接口完整性检查</title>
          <pubDate>Sun, 10 Mar 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-03-10-go-interface-check/</link>
          <guid>https://inasa.dev/posts/24-03-10-go-interface-check/</guid>
          <description xml:base="https://inasa.dev/posts/24-03-10-go-interface-check/">&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Shape&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-interface z-go&quot;&gt;interface&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Sides&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Area&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Square&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;len&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Square&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Sides&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;4&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-language z-blank z-go&quot;&gt;_&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Shape&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Square&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;s&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Square&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%d&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Sides&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;声明一个&lt;code&gt;_&lt;&#x2F;code&gt;变量（用不到），其会把一个&lt;code&gt;nil&lt;&#x2F;code&gt;的空指针，从&lt;code&gt;Square&lt;&#x2F;code&gt;转成&lt;code&gt;Shape&lt;&#x2F;code&gt;，这样，如果没有实现完相关的接口方法，编译器就会报错：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;cannot&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; use (&lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;*&lt;&#x2F;span&gt;Square&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)&lt;span class=&quot;z-punctuation z-definition z-compound z-begin z-shell&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-compound z-end z-shell&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; (type &lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;*&lt;&#x2F;span&gt;Square&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;) &lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;as&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; type Shape in assignment: &lt;span class=&quot;z-keyword z-operator z-regexp z-quantifier z-shell&quot;&gt;*&lt;&#x2F;span&gt;Square does not implement Shape (missing Area method&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;&#x2F;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</description>
      </item>
      <item>
          <title>Go | 检测当前系统位数</title>
          <pubDate>Sat, 09 Mar 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-03-09-go-check-os-bits/</link>
          <guid>https://inasa.dev/posts/24-03-09-go-check-os-bits/</guid>
          <description xml:base="https://inasa.dev/posts/24-03-09-go-check-os-bits/">&lt;h2 id=&quot;sheng-ming-yi-ge-chang-liang-lai-biao-shi-dang-qian-cao-zuo-xi-tong-de-wei-shu&quot;&gt;声明一个常量来表示当前操作系统的位数&lt;a class=&quot;zola-anchor&quot; href=&quot;#sheng-ming-yi-ge-chang-liang-lai-biao-shi-dang-qian-cao-zuo-xi-tong-de-wei-shu&quot; aria-label=&quot;Anchor link for: sheng-ming-yi-ge-chang-liang-lai-biao-shi-dang-qian-cao-zuo-xi-tong-de-wei-shu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-const z-go&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-declaration z-go&quot;&gt;NativeWordBits&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;32&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;^&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;63&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 64 or 32 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;^uint(0)&lt;&#x2F;code&gt;：对于无符号整型 uint(0)（其所有位都是0），按位取反操作会产生一个所有位都是1的数字。这个结果的数值上等同于 uint 能表示的最大值。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;&amp;gt;&amp;gt; 63&lt;&#x2F;code&gt;：这个操作的结果依赖于 uint 的大小：
&lt;ul&gt;
&lt;li&gt;在64位平台上，uint 类型为64位，&lt;code&gt;^uint(0)&lt;&#x2F;code&gt; 产生一个所有位都为1的64位数字。向右移动63位后，最左边的一位（最高位）会移动到最右边，结果为1（二进制的000...001）&lt;&#x2F;li&gt;
&lt;li&gt;在32位平台上，尽管仍然执行相同的操作，但是由于 uint 的大小只有32位，所以这个操作实际上产生的结果是 0，因为32位无法表示一个向右移动了63位的值&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;32 &amp;lt;&amp;lt; (... &amp;gt;&amp;gt; 63)&lt;&#x2F;code&gt;：最终这个表达式将32左移上一步的结果。在32位平台上，由于上一步的结果是 0，&lt;code&gt;32 &amp;lt;&amp;lt; 0&lt;&#x2F;code&gt; 保持不变，仍然是 32。这反映了32位系统的字长。在64位平台上，上一步的结果是 1，因此 &lt;code&gt;32 &amp;lt;&amp;lt; 1&lt;&#x2F;code&gt; 相当于将32乘以2，结果是 64。这反映了64位系统的字长。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h2 id=&quot;jian-cha-dang-qian-cao-zuo-xi-tong-shi-32wei-de-huan-shi-64wei-de&quot;&gt;检查当前操作系统是32位的还是64位的&lt;a class=&quot;zola-anchor&quot; href=&quot;#jian-cha-dang-qian-cao-zuo-xi-tong-shi-32wei-de-huan-shi-64wei-de&quot; aria-label=&quot;Anchor link for: jian-cha-dang-qian-cao-zuo-xi-tong-shi-32wei-de-huan-shi-64wei-de&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-const z-go&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-declaration z-go&quot;&gt;Is64bitOS&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;^&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;63&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-const z-go&quot;&gt;const&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-constant z-declaration z-go&quot;&gt;Is32bitOS&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;^&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uint&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;32&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;Go101&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Go | 协程和延迟调用的实参的估值时刻</title>
          <pubDate>Sat, 09 Mar 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-03-09-go-goroutine-defer/</link>
          <guid>https://inasa.dev/posts/24-03-09-go-goroutine-defer/</guid>
          <description xml:base="https://inasa.dev/posts/24-03-09-go-goroutine-defer/">&lt;ul&gt;
&lt;li&gt;一个延迟调用的实参是在此调用对应的延迟调用语句被执行时被估值的。 或者说，它们是在此延迟调用被推入延迟调用队列时被估值的。 这些被估值的结果将在以后此延迟调用被执行的时候使用。&lt;&#x2F;li&gt;
&lt;li&gt;一个匿名函数体内的表达式是在此函数被执行的时候才会被逐渐估值的，不管此函数是被普通调用还是延迟&#x2F;协程调用。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;fmt&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;++&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;defer&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;a:&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;++&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;defer&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;                &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;b:&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;            &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;输出&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;a:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 2 &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;a:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 1 &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;a:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 0 &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;b:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 3 &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;b:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 3 &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;b:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; 3 &lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;第一个循环中的i是在fmt.Println函数调用被推入延迟调用队列的时候估的值&lt;&#x2F;li&gt;
&lt;li&gt;第二个循环中的i是在第二个匿名函数调用的退出阶段估的值（此时循环变量i的值已经变为3）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;修改1&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;++&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;defer&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 此i为形参i，非实参循环变量i。 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;b:&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;修改2&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-go&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;++&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 在下面的调用中，左i遮挡了右i。 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; &amp;lt;=&amp;gt; var i = i 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;defer&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 此i为上面的左i，非循环变量i。 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;        &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Println&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;b:&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;Go101&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Go | nocopy机制</title>
          <pubDate>Sat, 09 Mar 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-03-09-go-nocopy/</link>
          <guid>https://inasa.dev/posts/24-03-09-go-nocopy/</guid>
          <description xml:base="https://inasa.dev/posts/24-03-09-go-nocopy/">&lt;p&gt;如何保证&lt;code&gt;nocopy&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;runtime-checking&quot;&gt;runtime checking&lt;a class=&quot;zola-anchor&quot; href=&quot;#runtime-checking&quot; aria-label=&quot;Anchor link for: runtime-checking&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;strings-builderzhong-copyjian-cha&quot;&gt;strings.Builder中copy检查&lt;a class=&quot;zola-anchor&quot; href=&quot;#strings-builderzhong-copyjian-cha&quot; aria-label=&quot;Anchor link for: strings-builderzhong-copyjian-cha&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;a&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;strings&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Builder&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Write&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;b&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;a&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Write&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;b&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 运行报错：panic: strings: illegal use of non-zero Builder copied by value
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;源码&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Builder&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;addr&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Builder&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; of receiver, to detect copies by value
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;buf&lt;&#x2F;span&gt;  &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;b&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Builder&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;copyCheck&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;addr&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;==&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; This hack works around a failing of Go&amp;#39;s escape analysis
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; that was causing b to escape and be heap allocated.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; See issue 23382.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; TODO: once issue 7921 is fixed, this should be reverted to
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; just &amp;quot;b.addr = b&amp;quot;.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;addr&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Builder&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;noescape&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;unsafe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;else&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;addr&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;panic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;strings: illegal use of non-zero Builder copied by value&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Write appends the contents of p to b&amp;#39;s buffer.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Write always returns len(p), nil.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;b&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Builder&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Write&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;p&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-brackets z-begin z-go&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-brackets z-end z-go&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;byte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;copyCheck&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;buf&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;append&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;buf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-variadic z-go&quot;&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;len&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;p&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-language z-go&quot;&gt;nil&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;addr&lt;&#x2F;code&gt;是一个指向自身的指针。当a复制给b时，a和b本身是不同的对象。因此，&lt;code&gt;b.addr&lt;&#x2F;code&gt;实际还是指向a的指针，这就会触发条件&lt;code&gt;b.addr!=b&lt;&#x2F;code&gt;，造成&lt;code&gt;panic&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sync-condzhong-copyjian-cha&quot;&gt;sync.Cond中copy检查&lt;a class=&quot;zola-anchor&quot; href=&quot;#sync-condzhong-copyjian-cha&quot; aria-label=&quot;Anchor link for: sync-condzhong-copyjian-cha&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;Cond&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;noCopy&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; L is held while observing or changing the condition
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;L&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;Locker&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;notify&lt;&#x2F;span&gt;  &lt;span class=&quot;z-storage z-type z-go&quot;&gt;notifyList&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;checker&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;copyChecker&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;copyChecker&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;c&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;copyChecker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;check&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Check if c has been copied in three steps:
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 1. The first comparison is the fast-path. If c has been initialized and not copied, this will return immediately. Otherwise, c is either not initialized, or has been copied.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 2. Ensure c is initialized. If the CAS succeeds, we&amp;#39;re done. If it fails, c was either initialized concurrently and we simply lost the race, or c has been copied.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 3. Do step 1 again. Now that c is definitely initialized, if this fails, c was copied.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;unsafe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;atomic&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;CompareAndSwapUintptr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;unsafe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;!=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;unsafe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;		&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-function z-builtin z-go&quot;&gt;panic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;sync.Cond is copied&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;定义一个相似的结构体对象，来探究这里的&lt;code&gt;check&lt;&#x2F;code&gt;函数究竟是如何做&lt;code&gt;copy&lt;&#x2F;code&gt;检查的。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;cond&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;checker&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;copyChecker&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;copyChecker&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-go&quot;&gt;c&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;copyChecker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;check&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;Before: c: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%12v&lt;&#x2F;span&gt;, *c: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%12v&lt;&#x2F;span&gt;, uintptr(*c): &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%12v&lt;&#x2F;span&gt;, uintptr(unsafe.Pointer(c)): &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%12v&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;unsafe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;swapped&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;atomic&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;CompareAndSwapUintptr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;unsafe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;fmt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Printf&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;After : c: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%12v&lt;&#x2F;span&gt;, *c: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%12v&lt;&#x2F;span&gt;, uintptr(*c): &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%12v&lt;&#x2F;span&gt;, uintptr(unsafe.Pointer(c)): &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%12v&lt;&#x2F;span&gt;, swapped: &lt;span class=&quot;z-constant z-other z-placeholder z-go&quot;&gt;%12v&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape z-go&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;unsafe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;swapped&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;a&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;cond&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;checker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;check&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;b&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;a&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;checker&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;check&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 输出
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Before&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;c0000b4008&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;            &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;            &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;unsafe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;824634458120&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;After&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;c0000b4008&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;824634458120&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;824634458120&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;unsafe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;824634458120&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;swapped&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;         &lt;span class=&quot;z-constant z-language z-go&quot;&gt;true&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Before&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;c0000b4040&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;824634458120&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;824634458120&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;unsafe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;824634458176&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;After&lt;&#x2F;span&gt; &lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-hexadecimal z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-numeric z-base z-go&quot;&gt;0x&lt;&#x2F;span&gt;c0000b4040&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;824634458120&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;824634458120&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;&lt;span class=&quot;z-support z-type z-builtin z-go&quot;&gt;uintptr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;unsafe&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Pointer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;824634458176&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;swapped&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;        &lt;span class=&quot;z-constant z-language z-go&quot;&gt;false&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;当a被b&lt;code&gt;copy&lt;&#x2F;code&gt;之后，&lt;code&gt;uintptr(*c)&lt;&#x2F;code&gt;和&lt;code&gt;uintptr(unsafe.Pointer(c))&lt;&#x2F;code&gt;的值是不同的，通过&lt;code&gt;uint&lt;&#x2F;code&gt;对象的原子比较方法&lt;code&gt;CompareAndSwapUintptr&lt;&#x2F;code&gt;将返回&lt;code&gt;false&lt;&#x2F;code&gt;，它证明了对象a被&lt;code&gt;copy&lt;&#x2F;code&gt;过，从而调用&lt;code&gt;panic&lt;&#x2F;code&gt;保护&lt;code&gt;sync.Cond&lt;&#x2F;code&gt;不被复制。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;go-vet-checking&quot;&gt;go vet checking&lt;a class=&quot;zola-anchor&quot; href=&quot;#go-vet-checking&quot; aria-label=&quot;Anchor link for: go-vet-checking&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; noCopy may be added to structs which must not be copied
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; after the first use.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; See https:&#x2F;&#x2F;golang.org&#x2F;issues&#x2F;8005#issuecomment-190753527
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; for details.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Note that it must not be embedded, due to the Lock and Unlock methods.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; Lock is a no-op used by -copylocks checker from `go vet`.
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Lock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;   &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Unlock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;runtime&lt;&#x2F;code&gt;时的&lt;code&gt;copy&lt;&#x2F;code&gt;检查虽然很重要，但是，该操作会影响程序的执行性能。&lt;&#x2F;p&gt;
&lt;p&gt;对于其他需要&lt;code&gt;nocopy&lt;&#x2F;code&gt;对象类型来说，使用&lt;code&gt;go vet&lt;&#x2F;code&gt;工具来做静态编译检查。&lt;&#x2F;p&gt;
&lt;p&gt;具体实施来说，就是该对象，或对象中存在&lt;code&gt;filed&lt;&#x2F;code&gt;，它拥有&lt;code&gt;Lock()&lt;&#x2F;code&gt;和&lt;code&gt;Unlock()&lt;&#x2F;code&gt;方法，即实现&lt;code&gt;sync.Locker&lt;&#x2F;code&gt;接口。之后，可以通过&lt;code&gt;go vet&lt;&#x2F;code&gt;功能，来检查代码中该对象是否有被&lt;code&gt;copy&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;jing-tai-jian-cha&quot;&gt;静态检查&lt;a class=&quot;zola-anchor&quot; href=&quot;#jing-tai-jian-cha&quot; aria-label=&quot;Anchor link for: jing-tai-jian-cha&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; wg.go
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-package z-go&quot;&gt;package&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;main&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-other z-import z-go&quot;&gt;import&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;sync&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-storage z-type z-keyword z-var z-go&quot;&gt;var&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;sm&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;sync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;Mutex&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;sm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Lock&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;sm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Unlock&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-declaration z-go&quot;&gt;sm2&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-go&quot;&gt;:=&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;sm&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;	&lt;span class=&quot;z-variable z-other z-go&quot;&gt;sm2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-function z-go&quot;&gt;Lock&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;该代码运行时，不会报错，但是却存在安全隐患。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; go vet wg.go&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt; &lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt; command-line-arguments&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;.&#x2F;wg.go:9:9:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; assignment copies lock value to sm2: sync.Mutex&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;因此，定义某对象不能被&lt;code&gt;copy&lt;&#x2F;code&gt;，就可以嵌入&lt;code&gt;noCopy&lt;&#x2F;code&gt;结构体，最终通过&lt;code&gt;go vet&lt;&#x2F;code&gt;进行&lt;code&gt;copy&lt;&#x2F;code&gt;检查。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Lock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-function z-go&quot;&gt;func&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-declaration z-go&quot;&gt; &lt;span class=&quot;z-entity z-name z-function z-go&quot;&gt;Unlock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-type z-go&quot;&gt;MyType&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-keyword z-struct z-go&quot;&gt;struct&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;   &lt;span class=&quot;z-variable z-other z-member z-declaration z-go&quot;&gt;noCopy&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-go&quot;&gt;noCopy&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;   &lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-type z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</description>
      </item>
      <item>
          <title>Gitlab | 升级</title>
          <pubDate>Thu, 01 Feb 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-02-01-gitlab-upgrade/</link>
          <guid>https://inasa.dev/posts/24-02-01-gitlab-upgrade/</guid>
          <description xml:base="https://inasa.dev/posts/24-02-01-gitlab-upgrade/">&lt;h1 id=&quot;que-ren-dang-qian-ban-ben&quot;&gt;确认当前版本&lt;a class=&quot;zola-anchor&quot; href=&quot;#que-ren-dang-qian-ban-ben&quot; aria-label=&quot;Anchor link for: que-ren-dang-qian-ban-ben&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;可以使用管理员账户查看&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;进入机器后使用命令查看&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cat &#x2F;opt&#x2F;gitlab&#x2F;embedded&#x2F;service&#x2F;gitlab-rails&#x2F;VERSION
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;kai-shi-sheng-ji&quot;&gt;开始升级&lt;a class=&quot;zola-anchor&quot; href=&quot;#kai-shi-sheng-ji&quot; aria-label=&quot;Anchor link for: kai-shi-sheng-ji&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;使用官方提供的&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;gitlab-com.gitlab.io&#x2F;support&#x2F;toolbox&#x2F;upgrade-path&quot;&gt;工具&lt;&#x2F;a&gt;一次进行升级&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;gitlab-com.gitlab.io&#x2F;support&#x2F;toolbox&#x2F;upgrade-path&#x2F;&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;docs.gitlab.com&#x2F;ee&#x2F;update&#x2F;index.html#upgrade-based-on-installation-method&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Git | 给公共库添加版本号</title>
          <pubDate>Wed, 24 Jan 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-01-24-git-add-version/</link>
          <guid>https://inasa.dev/posts/24-01-24-git-add-version/</guid>
          <description xml:base="https://inasa.dev/posts/24-01-24-git-add-version/">&lt;p&gt;使用 &lt;code&gt;git tag&lt;&#x2F;code&gt; 命令来添加一个版本号&lt;&#x2F;p&gt;
&lt;p&gt;例如，如果添加版本号 &lt;code&gt;v1.0.0&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;git tag v1.0.0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;git push origin v1.0.0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;获取库时，指定版本号&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;go get github.com&#x2F;yourusername&#x2F;yourlibrary@v1.0.0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Go 的版本控制遵循语义化版本规范，所以版本号应该遵循 &lt;code&gt;MAJOR.MINOR.PATCH&lt;&#x2F;code&gt; 的格式。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;MAJOR&lt;&#x2F;code&gt; 版本号表示做了不兼容的 API 更改&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;MINOR&lt;&#x2F;code&gt; 版本号表示做了向下兼容的功能添加&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;PATCH&lt;&#x2F;code&gt; 版本号表示做了向下兼容的问题修复&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Debian | Install custom CA</title>
          <pubDate>Tue, 23 Jan 2024 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/24-01-23-debian-install-ca/</link>
          <guid>https://inasa.dev/posts/24-01-23-debian-install-ca/</guid>
          <description xml:base="https://inasa.dev/posts/24-01-23-debian-install-ca/">&lt;ol&gt;
&lt;li&gt;复制&lt;code&gt;my_own_ca.crt&lt;&#x2F;code&gt;到&lt;code&gt;&#x2F;usr&#x2F;local&#x2F;share&#x2F;ca-certificates&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;执行&lt;code&gt;update-ca-certificates&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;code&gt;update-ca-certificates&lt;&#x2F;code&gt; 创建必要的 &lt;code&gt;simlink&lt;&#x2F;code&gt; 并更新 &lt;code&gt;&#x2F;etc&#x2F;ssl&#x2F;certs&#x2F;ca-certificates.crt&lt;&#x2F;code&gt; 文件。&lt;&#x2F;p&gt;
&lt;p&gt;验证&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;etc&#x2F;ssl&#x2F;certs# ls -alFh | grep my_own_ca
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;lrwxrwxrwx 1 root root   40 Jan 23 10:49  my_own_ca.pem -&amp;gt; &#x2F;usr&#x2F;local&#x2F;share&#x2F;ca-certificates&#x2F;my_own_ca.crt
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;openssl crl2pkcs7 -nocrl -certfile &#x2F;etc&#x2F;ssl&#x2F;certs&#x2F;ca-certificates.crt | openssl pkcs7 -print_certs -noout
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;unix.stackexchange.com&#x2F;questions&#x2F;688608&#x2F;is-it-possible-to-install-a-custom-ca-certificate-without-the-ca-certificates-pa&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Git | Commit Message style</title>
          <pubDate>Wed, 13 Sep 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-09-13-git-commit-message-style/</link>
          <guid>https://inasa.dev/posts/23-09-13-git-commit-message-style/</guid>
          <description xml:base="https://inasa.dev/posts/23-09-13-git-commit-message-style/">&lt;h3 id=&quot;gai-yao&quot;&gt;概要&lt;a class=&quot;zola-anchor&quot; href=&quot;#gai-yao&quot; aria-label=&quot;Anchor link for: gai-yao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;每次提交，&lt;code&gt;Commit message&lt;&#x2F;code&gt; 都包括三个部分：&lt;code&gt;Header&lt;&#x2F;code&gt;，&lt;code&gt;Body&lt;&#x2F;code&gt; 和 &lt;code&gt;Footer&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword z-type z-go&quot;&gt;type&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;scope&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;subject&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 空一行
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;body&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 空一行
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;footer&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;其中，&lt;code&gt;Header&lt;&#x2F;code&gt; 是必需的，&lt;code&gt;Body&lt;&#x2F;code&gt; 和 &lt;code&gt;Footer&lt;&#x2F;code&gt; 可以省略。&lt;&#x2F;p&gt;
&lt;p&gt;不管是哪一个部分，任何一行都不得超过72个字符（或100个字符）。这是为了避免自动换行影响美观。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;header&quot;&gt;Header&lt;a class=&quot;zola-anchor&quot; href=&quot;#header&quot; aria-label=&quot;Anchor link for: header&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;Header&lt;&#x2F;code&gt;部分只有一行，包括三个字段：&lt;code&gt;type&lt;&#x2F;code&gt;（必需）、&lt;code&gt;scope&lt;&#x2F;code&gt;（可选）和&lt;code&gt;subject&lt;&#x2F;code&gt;（必需）。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;type&quot;&gt;type&lt;a class=&quot;zola-anchor&quot; href=&quot;#type&quot; aria-label=&quot;Anchor link for: type&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;code&gt;type&lt;&#x2F;code&gt;用于说明 &lt;code&gt;commit&lt;&#x2F;code&gt; 的类别，只允许使用下面7个标识。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;feat&lt;&#x2F;code&gt;：新功能（feature）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;fix&lt;&#x2F;code&gt;：修补bug&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;docs&lt;&#x2F;code&gt;：文档（documentation）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;style&lt;&#x2F;code&gt;： 格式（不影响代码运行的变动）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;refactor&lt;&#x2F;code&gt;：重构（即不是新增功能，也不是修改bug的代码变动）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;test&lt;&#x2F;code&gt;：增加测试&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;chore&lt;&#x2F;code&gt;：构建过程或辅助工具的变动&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;如果&lt;code&gt;type&lt;&#x2F;code&gt;为&lt;code&gt;feat&lt;&#x2F;code&gt;和&lt;code&gt;fix&lt;&#x2F;code&gt;，则该 &lt;code&gt;commit&lt;&#x2F;code&gt; 将肯定出现在 &lt;code&gt;Change log&lt;&#x2F;code&gt; 之中。其他情况（&lt;code&gt;docs&lt;&#x2F;code&gt;、&lt;code&gt;chore&lt;&#x2F;code&gt;、&lt;code&gt;style&lt;&#x2F;code&gt;、&lt;code&gt;refactor&lt;&#x2F;code&gt;、&lt;code&gt;test&lt;&#x2F;code&gt;）由你决定，要不要放入 &lt;code&gt;Change log&lt;&#x2F;code&gt;，建议是不要。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;scope&quot;&gt;scope&lt;a class=&quot;zola-anchor&quot; href=&quot;#scope&quot; aria-label=&quot;Anchor link for: scope&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;code&gt;scope&lt;&#x2F;code&gt;用于说明 &lt;code&gt;commit&lt;&#x2F;code&gt; 影响的范围，比如数据层、控制层、视图层等等，视项目不同而不同。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;subject&quot;&gt;subject&lt;a class=&quot;zola-anchor&quot; href=&quot;#subject&quot; aria-label=&quot;Anchor link for: subject&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;code&gt;subject&lt;&#x2F;code&gt;是 &lt;code&gt;commit&lt;&#x2F;code&gt; 目的的简短描述，不超过50个字符。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;以动词开头，使用第一人称现在时，比如&lt;code&gt;change&lt;&#x2F;code&gt;，而不是&lt;code&gt;changed&lt;&#x2F;code&gt;或&lt;code&gt;changes&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;第一个字母小写&lt;&#x2F;li&gt;
&lt;li&gt;结尾不加句号（&lt;strong&gt;&lt;code&gt;.&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt;）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;body&quot;&gt;Body&lt;a class=&quot;zola-anchor&quot; href=&quot;#body&quot; aria-label=&quot;Anchor link for: body&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;Body&lt;&#x2F;code&gt; 部分是对本次 &lt;code&gt;commit&lt;&#x2F;code&gt; 的详细描述，可以分成多行。下面是一个范例。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;More&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;detailed&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;explanatory&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;text&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;if&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;necessary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;  &lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Wrap&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;it&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;to&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;about&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;72&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;characters&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;or&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;so&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt; 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;Further&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;paragraphs&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;come&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;after&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;blank&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;lines&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Bullet&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;points&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;are&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;okay&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;too&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;-&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Use&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;a&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;hanging&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;indent&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;有两个注意点。&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;使用第一人称现在时，比如使用&lt;code&gt;change&lt;&#x2F;code&gt;而不是&lt;code&gt;changed&lt;&#x2F;code&gt;或&lt;code&gt;changes&lt;&#x2F;code&gt;。&lt;&#x2F;li&gt;
&lt;li&gt;应该说明代码变动的动机，以及与以前行为的对比。&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;footer&quot;&gt;Footer&lt;a class=&quot;zola-anchor&quot; href=&quot;#footer&quot; aria-label=&quot;Anchor link for: footer&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;Footer&lt;&#x2F;code&gt; 部分只用于两种情况。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;bu-jian-rong-bian-dong&quot;&gt;不兼容变动&lt;a class=&quot;zola-anchor&quot; href=&quot;#bu-jian-rong-bian-dong&quot; aria-label=&quot;Anchor link for: bu-jian-rong-bian-dong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;如果当前代码与上一个版本不兼容，则 &lt;code&gt;Footer&lt;&#x2F;code&gt; 部分以&lt;code&gt;BREAKING CHANGE&lt;&#x2F;code&gt;开头，后面是对变动的描述、以及变动理由和迁移方法。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;BREAKING&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;CHANGE&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;isolate&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;scope&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;bindings&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;definition&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;has&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;changed&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-member z-go&quot;&gt;To&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;migrate&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;the&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;code&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;follow&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;the&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;example&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;below&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;Before&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;scope&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;myAttr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-character z-go&quot;&gt;&amp;#39;attribute&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;After&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;scope&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-block z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-braces z-begin z-go&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;      &lt;span class=&quot;z-variable z-other z-go&quot;&gt;myAttr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-character z-go&quot;&gt;&amp;#39;@&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-meta z-block z-go&quot;&gt;    &lt;span class=&quot;z-punctuation z-section z-braces z-end z-go&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;    &lt;span class=&quot;z-variable z-other z-go&quot;&gt;The&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;removed&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-other z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-go&quot;&gt;`&lt;&#x2F;span&gt;inject&lt;span class=&quot;z-punctuation z-definition z-string z-end z-go&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;wasn&lt;&#x2F;span&gt;&amp;#39;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;t&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;generaly&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;useful&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-control z-go&quot;&gt;for&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;directives&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;so&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;there&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;should&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;be&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;no&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;code&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;using&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;it&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor z-dot z-go&quot;&gt;.&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;guan-bi-issue&quot;&gt;关闭 Issue&lt;a class=&quot;zola-anchor&quot; href=&quot;#guan-bi-issue&quot; aria-label=&quot;Anchor link for: guan-bi-issue&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;如果当前 &lt;code&gt;commit&lt;&#x2F;code&gt; 针对某个&lt;code&gt;issue&lt;&#x2F;code&gt;，那么可以在 &lt;code&gt;Footer&lt;&#x2F;code&gt; 部分关闭这个 &lt;code&gt;issue&lt;&#x2F;code&gt; 。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Closes&lt;&#x2F;span&gt; #&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;234&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;也可以一次关闭多个 &lt;strong&gt;&lt;code&gt;issue&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; 。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;Closes&lt;&#x2F;span&gt; #&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;123&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; #&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;245&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;,&lt;&#x2F;span&gt; #&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;992&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h3 id=&quot;revert&quot;&gt;Revert&lt;a class=&quot;zola-anchor&quot; href=&quot;#revert&quot; aria-label=&quot;Anchor link for: revert&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;如果当前 &lt;code&gt;commit&lt;&#x2F;code&gt; 用于撤销以前的 &lt;code&gt;commit&lt;&#x2F;code&gt;，则必须以&lt;code&gt;revert:&lt;&#x2F;code&gt; 开头，后面跟着被撤销 &lt;code&gt;Commit&lt;&#x2F;code&gt; 的 &lt;code&gt;Header&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;revert&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-function z-go&quot;&gt;feat&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-begin z-go&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;pencil&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-parens z-end z-go&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-go&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;add&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-character z-go&quot;&gt;&amp;#39;graphiteWidth&amp;#39;&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;option&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;This&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;reverts&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-other z-go&quot;&gt;commit&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;667&lt;&#x2F;span&gt;ecc&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;1654&lt;&#x2F;span&gt;a&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;317&lt;&#x2F;span&gt;a&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;13331&lt;&#x2F;span&gt;b&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;17617&lt;&#x2F;span&gt;d&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;973392&lt;&#x2F;span&gt;f&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-go&quot;&gt;415&lt;&#x2F;span&gt;f&lt;span class=&quot;z-constant z-numeric z-float z-decimal z-go&quot;&gt;02&lt;span class=&quot;z-punctuation z-separator z-decimal z-go&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;Body&lt;&#x2F;code&gt;部分的格式是固定的，必须写成&lt;code&gt;This reverts commit &amp;lt;hash&amp;gt;&lt;&#x2F;code&gt;，其中的&lt;code&gt;hash&lt;&#x2F;code&gt;是被撤销 &lt;code&gt;commit&lt;&#x2F;code&gt; 的 &lt;code&gt;SHA&lt;&#x2F;code&gt; 标识符。&lt;&#x2F;p&gt;
&lt;p&gt;如果当前 &lt;code&gt;commit&lt;&#x2F;code&gt; 与被撤销的 &lt;code&gt;commit&lt;&#x2F;code&gt;，在同一个发布（&lt;code&gt;release&lt;&#x2F;code&gt;）里面，那么它们都不会出现在 &lt;code&gt;Change log&lt;&#x2F;code&gt; 里面。如果两者在不同的发布，那么当前 &lt;code&gt;commit&lt;&#x2F;code&gt;，会出现在 &lt;code&gt;Change log&lt;&#x2F;code&gt; 的&lt;code&gt;Reverts&lt;&#x2F;code&gt; 小标题下面。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;www.ruanyifeng.com&#x2F;blog&#x2F;2016&#x2F;01&#x2F;commit_message_change_log.html&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Rust | Clone vs Copy</title>
          <pubDate>Wed, 13 Sep 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-09-13-rust-copy-clone/</link>
          <guid>https://inasa.dev/posts/23-09-13-rust-copy-clone/</guid>
          <description xml:base="https://inasa.dev/posts/23-09-13-rust-copy-clone/">&lt;h3 id=&quot;copyde-han-yi&quot;&gt;Copy的含义&lt;a class=&quot;zola-anchor&quot; href=&quot;#copyde-han-yi&quot; aria-label=&quot;Anchor link for: copyde-han-yi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;Copy&lt;&#x2F;code&gt;的全名是&lt;code&gt;std::marker::Copy&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;std::marker&lt;&#x2F;code&gt;模块里面所有的&lt;code&gt;trait&lt;&#x2F;code&gt;都是特殊的&lt;code&gt;trait&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;它们是跟编译器密切绑定的，&lt;code&gt;impl&lt;&#x2F;code&gt;这些&lt;code&gt;trait&lt;&#x2F;code&gt;对编译器的行为有重要影响。在编译器眼里，它们与其他的&lt;code&gt;trait&lt;&#x2F;code&gt;不一样。这几个&lt;code&gt;trait&lt;&#x2F;code&gt;内部都没有方法，它们的唯一任务是给类型打一个“标记”，表明它符合某种约定——这些约定会影响编译器的静态检查以及代码生成&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;那么，&lt;code&gt;Copy&lt;&#x2F;code&gt;这个&lt;code&gt;trait&lt;&#x2F;code&gt;在编译器的眼里代表的是什么意思呢？&lt;&#x2F;p&gt;
&lt;p&gt;简单点总结就是，如果一个类型&lt;code&gt;impl&lt;&#x2F;code&gt;了&lt;code&gt;Copy trait&lt;&#x2F;code&gt;，意味着任何时候，我们都可以通过简单的内存复制（在C语言里按字节复制&lt;code&gt;memcpy&lt;&#x2F;code&gt;）实现该类型的复制，并且不会产生任何内存安全问题。&lt;&#x2F;p&gt;
&lt;p&gt;一旦一个类型实现了&lt;code&gt;Copy trait&lt;&#x2F;code&gt;，那么它在变量绑定、函数参数传递、函数返回值传递等场景下，都是&lt;code&gt;copy&lt;&#x2F;code&gt;语义，而不再是默认的&lt;code&gt;move&lt;&#x2F;code&gt;语义。&lt;&#x2F;p&gt;
&lt;p&gt;最简单的赋值语句&lt;code&gt;x = y&lt;&#x2F;code&gt;来说明&lt;code&gt;move&lt;&#x2F;code&gt;语义和&lt;code&gt;copy&lt;&#x2F;code&gt;语义的根本区别&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;move&lt;&#x2F;code&gt;语义是“&lt;strong&gt;剪切、粘贴&lt;&#x2F;strong&gt;”操作，变量&lt;code&gt;y&lt;&#x2F;code&gt;把所有权递交给了&lt;code&gt;x&lt;&#x2F;code&gt;之后，&lt;code&gt;y&lt;&#x2F;code&gt;就彻底失效了，后面继续使用&lt;code&gt;y&lt;&#x2F;code&gt;就会出编译错误&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;copy&lt;&#x2F;code&gt;语义是“&lt;strong&gt;复制、粘贴&lt;&#x2F;strong&gt;”操作，变量&lt;code&gt;y&lt;&#x2F;code&gt;把所有权递交给了&lt;code&gt;x&lt;&#x2F;code&gt;之后，它自己还留了一个副本，在这句赋值语句之后，&lt;code&gt;x&lt;&#x2F;code&gt;和&lt;code&gt;y&lt;&#x2F;code&gt;依然都可以继续使用&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;在&lt;code&gt;Rust&lt;&#x2F;code&gt;里，&lt;code&gt;move&lt;&#x2F;code&gt;语义和&lt;code&gt;copy&lt;&#x2F;code&gt;语义具体执行的操作，是不允许由程序员自定义的。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;move&lt;&#x2F;code&gt;语义或者&lt;code&gt;copy&lt;&#x2F;code&gt;语义都是执行的&lt;code&gt;memcpy&lt;&#x2F;code&gt;，无法更改，这个过程中绝对不存在其他副作用。&lt;&#x2F;p&gt;
&lt;p&gt;如果考虑后端优化，在许多情况下，不必要的内存复制实际上已经彻底优化掉了，不必担心执行效率的问题。没有必要每次都把&lt;code&gt;move&lt;&#x2F;code&gt;或者&lt;code&gt;copy&lt;&#x2F;code&gt;操作与具体的汇编代码联系起来，因为场景不同，优化结果不同，生成的代码也是不同的。只需记住的是语义。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;copyde-shi-xian-tiao-jian&quot;&gt;Copy的实现条件&lt;a class=&quot;zola-anchor&quot; href=&quot;#copyde-shi-xian-tiao-jian&quot; aria-label=&quot;Anchor link for: copyde-shi-xian-tiao-jian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;并不是所有的类型都可以实现&lt;code&gt;Copy trait&lt;&#x2F;code&gt;。&lt;code&gt;Rust&lt;&#x2F;code&gt;规定，对于自定义类型，只有所有成员都实现了&lt;code&gt;Copy trait&lt;&#x2F;code&gt;，这个类型才有资格实现&lt;code&gt;Copy trait&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;常见的数字类型、&lt;code&gt;bool&lt;&#x2F;code&gt;类型、共享借用指针&lt;code&gt;&amp;amp;&lt;&#x2F;code&gt;，都是具有&lt;code&gt;Copy&lt;&#x2F;code&gt;属性的类型&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Box&lt;&#x2F;code&gt;、&lt;code&gt;Vec&lt;&#x2F;code&gt;、可写借用指针&lt;code&gt;&amp;amp;mut&lt;&#x2F;code&gt;等类型都是不具备&lt;code&gt;Copy&lt;&#x2F;code&gt;属性的类型&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;对于数组类型，如果内部的元素类型是&lt;code&gt;Copy&lt;&#x2F;code&gt;，那么这个数组也是&lt;code&gt;Copy&lt;&#x2F;code&gt;类型&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;对于元组&lt;code&gt;tuple&lt;&#x2F;code&gt;类型，如果每一个元素都是&lt;code&gt;Copy&lt;&#x2F;code&gt;类型，那么这个&lt;code&gt;tuple&lt;&#x2F;code&gt;也是&lt;code&gt;Copy&lt;&#x2F;code&gt;类型&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;struct&lt;&#x2F;code&gt;和&lt;code&gt;enum&lt;&#x2F;code&gt;类型不会自动实现&lt;code&gt;Copy trait&lt;&#x2F;code&gt;。只有当&lt;code&gt;struct&lt;&#x2F;code&gt;和&lt;code&gt;enum&lt;&#x2F;code&gt;内部的每个元素都是&lt;code&gt;Copy&lt;&#x2F;code&gt;类型时，编译器才允许我们针对此类型实现&lt;code&gt;Copy trait&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;    &lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-struct z-rust&quot;&gt;struct&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-struct z-rust&quot;&gt;T&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;i32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;    &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; t1 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; T&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; t2 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; t1&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; t1&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; t2&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;编译错误。原因是在&lt;code&gt;let t2 = t1&lt;&#x2F;code&gt;；这条语句中执行的是&lt;code&gt;move&lt;&#x2F;code&gt;语义。但是可以手动为它&lt;code&gt;impl Copy trait&lt;&#x2F;code&gt;，这样它就具备了&lt;code&gt;copy&lt;&#x2F;code&gt;语义&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;Rust&lt;&#x2F;code&gt;中只有&lt;code&gt;POD&lt;&#x2F;code&gt;（&lt;code&gt;C++&lt;&#x2F;code&gt;语言中的&lt;code&gt;Plain Old Data&lt;&#x2F;code&gt;）类型才有资格实现&lt;code&gt;Copy trait&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;在&lt;code&gt;Rust&lt;&#x2F;code&gt;中，如果一个类型只包含&lt;code&gt;POD&lt;&#x2F;code&gt;数据类型的成员，并且没有自定义析构函数，那它就是&lt;code&gt;POD&lt;&#x2F;code&gt;类型。&lt;&#x2F;p&gt;
&lt;p&gt;比如：整数、浮点数、只包含&lt;code&gt;POD&lt;&#x2F;code&gt;类型的数组等，都属于&lt;code&gt;POD&lt;&#x2F;code&gt;类型；而&lt;code&gt;Box&lt;&#x2F;code&gt; &lt;code&gt;String&lt;&#x2F;code&gt; &lt;code&gt;Vec&lt;&#x2F;code&gt;等不能按字节复制的类型，都不属于&lt;code&gt;POD&lt;&#x2F;code&gt;类型。&lt;&#x2F;p&gt;
&lt;p&gt;并不是所有满足&lt;code&gt;POD&lt;&#x2F;code&gt;的类型都应该实现&lt;code&gt;Copy trait&lt;&#x2F;code&gt;，是否实现&lt;code&gt;Copy&lt;&#x2F;code&gt;取决于&lt;em&gt;业务需求&lt;&#x2F;em&gt;。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;clonede-han-yi&quot;&gt;Clone的含义&lt;a class=&quot;zola-anchor&quot; href=&quot;#clonede-han-yi&quot; aria-label=&quot;Anchor link for: clonede-han-yi&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;code&gt;Clone&lt;&#x2F;code&gt;的全名是&lt;code&gt;std::clone::Clone&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;    &lt;span class=&quot;z-meta z-trait z-rust&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;pub&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-trait z-rust&quot;&gt;trait&lt;&#x2F;span&gt; &lt;span class=&quot;z-entity z-name z-trait z-rust&quot;&gt;Clone&lt;&#x2F;span&gt; : Sized &lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-trait z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;clone&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;self&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;span class=&quot;z-meta z-function z-return-type z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;Self&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-trait z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;clone_from&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; &lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;self&lt;&#x2F;span&gt;, &lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;Self&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-trait z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;            ＊&lt;span class=&quot;z-variable z-language z-rust&quot;&gt;self&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; source&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;clone&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-trait z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;        &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-trait z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;两个关联方法，分别是&lt;code&gt;clone_from&lt;&#x2F;code&gt;和&lt;code&gt;clone&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;clone_from&lt;&#x2F;code&gt;是有默认实现的，依赖于&lt;code&gt;clone&lt;&#x2F;code&gt;方法的实现&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;clone&lt;&#x2F;code&gt;方法没有默认实现，需要手动实现&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;code&gt;clone&lt;&#x2F;code&gt;方法一般用于“基于语义的复制”操作。所以，跟具体类型的作用息息相关。比如，对于&lt;code&gt;Box&lt;&#x2F;code&gt;类型，&lt;code&gt;clone&lt;&#x2F;code&gt;执行的是“深复制”；而对于&lt;code&gt;Rc&lt;&#x2F;code&gt;类型，&lt;code&gt;clone&lt;&#x2F;code&gt;做的事情就是把引用计数值加1。&lt;&#x2F;p&gt;
&lt;p&gt;虽然&lt;code&gt;Rust&lt;&#x2F;code&gt;中的&lt;code&gt;clone&lt;&#x2F;code&gt;方法一般是用来执行复制操作的，但是如果在自定义的&lt;code&gt;clone&lt;&#x2F;code&gt;函数中做点别的什么工作，编译器也没办法禁止。可以根据需要在&lt;code&gt;clone&lt;&#x2F;code&gt;函数中编写任意的逻辑。&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;对于实现了&lt;code&gt;copy&lt;&#x2F;code&gt;的类型，它的&lt;code&gt;clone&lt;&#x2F;code&gt;方法应该跟&lt;code&gt;copy&lt;&#x2F;code&gt;语义相容，等同于按字节复制&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;zi-dong-derive&quot;&gt;自动derive&lt;a class=&quot;zola-anchor&quot; href=&quot;#zi-dong-derive&quot; aria-label=&quot;Anchor link for: zi-dong-derive&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;绝大多数情况下，实现&lt;code&gt;Copy&lt;&#x2F;code&gt; &lt;code&gt;Clone&lt;&#x2F;code&gt;这样的&lt;code&gt;trait&lt;&#x2F;code&gt;都是一个重复而无聊的工作。因此，&lt;code&gt;Rust&lt;&#x2F;code&gt;提供了一个&lt;code&gt;attribute&lt;&#x2F;code&gt;，可以利用编译器自动生成这部分代码。示例如下：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;    &lt;span class=&quot;z-meta z-annotation z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-annotation z-rust&quot;&gt;#&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-annotation z-rust&quot;&gt;derive&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;Copy&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; Clone&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-annotation z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;    &lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-struct z-rust&quot;&gt;struct&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-entity z-name z-struct z-rust&quot;&gt;MyStruct&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-struct z-rust&quot;&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;i32&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;derive&lt;&#x2F;code&gt;会让编译器自动生成&lt;code&gt;impl Copy&lt;&#x2F;code&gt;和&lt;code&gt;impl Clone&lt;&#x2F;code&gt;这样的代码。自动生成的&lt;code&gt;clone&lt;&#x2F;code&gt;方法，会依次调用每个成员的&lt;code&gt;clone&lt;&#x2F;code&gt;方法。&lt;&#x2F;p&gt;
&lt;p&gt;通过&lt;code&gt;derive&lt;&#x2F;code&gt;方式自动实现&lt;code&gt;Copy&lt;&#x2F;code&gt;和手工实现&lt;code&gt;Copy&lt;&#x2F;code&gt;有微小的区别。当类型具有泛型参数的时候，比如&lt;code&gt;struct MyStruct&amp;lt;T&amp;gt;{}&lt;&#x2F;code&gt;，通过&lt;code&gt;derive&lt;&#x2F;code&gt;自动生成的代码会自动添加一个&lt;code&gt;T:Copy&lt;&#x2F;code&gt;的约束。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;zong-jie&quot;&gt;总结&lt;a class=&quot;zola-anchor&quot; href=&quot;#zong-jie&quot; aria-label=&quot;Anchor link for: zong-jie&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Copy&lt;&#x2F;code&gt;内部没有方法，&lt;code&gt;Clone&lt;&#x2F;code&gt;内部有两个方法&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Copy trait&lt;&#x2F;code&gt;是给编译器用的，告诉编译器这个类型默认采用&lt;code&gt;copy&lt;&#x2F;code&gt;语义，而不是&lt;code&gt;move&lt;&#x2F;code&gt;语义。&lt;code&gt;Clone trait&lt;&#x2F;code&gt;是给程序员用的，我们必须手动调用&lt;code&gt;clone&lt;&#x2F;code&gt;方法，它才能发挥作用&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Copy trait&lt;&#x2F;code&gt;不是想实现就能实现的，它对类型是有要求的，有些类型不可能&lt;code&gt;impl Copy&lt;&#x2F;code&gt;。而&lt;code&gt;Clone trait&lt;&#x2F;code&gt;则没有什么前提条件，任何类型都可以实现（&lt;code&gt;unsized&lt;&#x2F;code&gt;类型除外，因为无法使用&lt;code&gt;unsized&lt;&#x2F;code&gt;类型作为返回值）&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Copy trait&lt;&#x2F;code&gt;规定了这个类型在执行变量绑定、函数参数传递、函数返回等场景下的操作方式。即这个类型在这种场景下，必然执行的是“&lt;strong&gt;简单内存复制&lt;&#x2F;strong&gt;”操作，这是由编译器保证的，程序员无法控制。&lt;code&gt;Clone trait&lt;&#x2F;code&gt;里面的&lt;code&gt;clone&lt;&#x2F;code&gt;方法究竟会执行什么操作，则是取决于程序员自己写的逻辑。一般情况下，&lt;code&gt;clone&lt;&#x2F;code&gt;方法应该执行一个“深复制”操作，但这不是强制性的，如果你愿意，在里面启动一个人工智能程序都是有可能的&lt;&#x2F;li&gt;
&lt;li&gt;如果确实不需要&lt;code&gt;Clone trait&lt;&#x2F;code&gt;执行其他自定义操作（绝大多数情况都是这样），编译器提供了一个工具，我们可以在一个类型上添加&lt;code&gt;#[derive(Clone)]&lt;&#x2F;code&gt;，来让编译器自动生成那些重复的代码。编译器自动生成的&lt;code&gt;clone&lt;&#x2F;code&gt;方法非常机械，就是依次调用每个成员的&lt;code&gt;clone&lt;&#x2F;code&gt;方法&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Rust&lt;&#x2F;code&gt;语言规定了在&lt;code&gt;T: Copy&lt;&#x2F;code&gt;的情况下，&lt;code&gt;Clone trait&lt;&#x2F;code&gt;代表的含义。即：当某变量&lt;code&gt;t: T&lt;&#x2F;code&gt;符合&lt;code&gt;T: Copy&lt;&#x2F;code&gt;时，它调用&lt;code&gt;t.clone()&lt;&#x2F;code&gt; 方法的含义必须等同于“&lt;strong&gt;简单内存复制&lt;&#x2F;strong&gt;”。也就是说，&lt;code&gt;clone&lt;&#x2F;code&gt;的行为必须等同于&lt;code&gt;let x = std::ptr::read(&amp;amp;t);&lt;&#x2F;code&gt;，也等同于&lt;code&gt;let x = t;&lt;&#x2F;code&gt;。当&lt;code&gt;T: Copy&lt;&#x2F;code&gt;时，不要在&lt;code&gt;Clone trait&lt;&#x2F;code&gt;里面乱写逻辑。所以，当需要指定一个类型是&lt;code&gt;Copy&lt;&#x2F;code&gt;的时候，最好使用&lt;code&gt;#[derive(Copy,Clone)]&lt;&#x2F;code&gt;方式，避免手动实现&lt;code&gt;Clone&lt;&#x2F;code&gt;导致错误。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;深入浅出Rust&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>ClickHouse | ReplacingMergeTree使用记录</title>
          <pubDate>Sun, 13 Aug 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-08-13-clickhouse-replacingmergetree-note/</link>
          <guid>https://inasa.dev/posts/23-08-13-clickhouse-replacingmergetree-note/</guid>
          <description xml:base="https://inasa.dev/posts/23-08-13-clickhouse-replacingmergetree-note/">&lt;p&gt;删除具有相同排序键值（ORDER BY 表部分，而不是 PRIMARY KEY）的重复条目&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ENGINE = ReplacingMergeTree([ver [, is_deleted]])
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;ReplacingMergeTree&lt;&#x2F;code&gt;后面会跟一个或两个列&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ver&lt;&#x2F;code&gt;表示版本号的列&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;类型 &lt;code&gt;UInt*&lt;&#x2F;code&gt;、&lt;code&gt;Date&lt;&#x2F;code&gt;、&lt;code&gt;DateTime&lt;&#x2F;code&gt; 或 &lt;code&gt;DateTime64&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;如果ver未指定，则使用选择中的最后一个&lt;&#x2F;li&gt;
&lt;li&gt;如果ver已指定，则使用最大版本&lt;&#x2F;li&gt;
&lt;li&gt;这里可以参考官网的&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;clickhouse.com&#x2F;docs&#x2F;en&#x2F;engines&#x2F;table-engines&#x2F;mergetree-family&#x2F;replacingmergetree#ver&quot;&gt;示例&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;is_deleted&lt;&#x2F;code&gt;表示删除的状态&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;类型必须是 &lt;code&gt;UInt8&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;只有设置了&lt;code&gt;ver&lt;&#x2F;code&gt;才可以设置&lt;code&gt;is_deleted&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;合并期间使用的列名称，用于确定该行中的数据是否代表状态或要删除&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1&lt;&#x2F;code&gt; 是“已删除”行&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;0&lt;&#x2F;code&gt; 是“状态”行&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;当使用 &lt;code&gt;OPTIMIZE table {table_name} FINAL CLEANUP&lt;&#x2F;code&gt; 或 &lt;code&gt;OPTIMIZE table {table_name} FINAL&lt;&#x2F;code&gt; 时，或者引擎设置 &lt;code&gt;clean_deleted_rows&lt;&#x2F;code&gt; 设置为 &lt;code&gt;Always&lt;&#x2F;code&gt; 时，将删除该行&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;删除是异步的&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;默认一条insert插入的数据为同一个数据分区，不同insert插入的数据为不同的分区，所以ReplacingMergeTree是以分区为单位进行去重的，也就是说只有在相同的数据分区内，重复数据才可以被删除掉。只有数据合并完成后，才可以使用引擎特性进行去重。&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;修改&lt;code&gt;config.xml&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;lt;merge_tree&amp;gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;            &amp;lt;max_suspicious_broken_parts&amp;gt;5&amp;lt;&#x2F;max_suspicious_broken_parts&amp;gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;            &amp;lt;clean_deleted_rows&amp;gt;Always&amp;lt;&#x2F;clean_deleted_rows&amp;gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    &amp;lt;&#x2F;merge_tree&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;无论对数据进行什么操作，都必须增加版本。如果两个插入的行具有相同的版本号，则保留最后插入的行&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;如果指定了&lt;code&gt;ver&lt;&#x2F;code&gt;，但是没有指定&lt;code&gt;is_deleted&lt;&#x2F;code&gt;，旧的数据会依然保存在表里。&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;select * from {table_name}&#x2F;&#x2F;查出所有数据，包括新旧
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;select * from {table_name} final &#x2F;&#x2F;只查询新数据，感觉很慢，需要个好几秒
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;clickhouse.com&#x2F;docs&#x2F;en&#x2F;engines&#x2F;table-engines&#x2F;mergetree-family&#x2F;replacingmergetree&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;github.com&#x2F;ClickHouse&#x2F;ClickHouse&#x2F;issues&#x2F;8322&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;clickhouse.com&#x2F;docs&#x2F;en&#x2F;operations&#x2F;settings&#x2F;merge-tree-settings#clean_deleted_rows&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>ClickHouse | 为什么select的输出会被拆分</title>
          <pubDate>Sun, 13 Aug 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-08-13-clickhouse-select-split-output/</link>
          <guid>https://inasa.dev/posts/23-08-13-clickhouse-select-split-output/</guid>
          <description xml:base="https://inasa.dev/posts/23-08-13-clickhouse-select-split-output/">&lt;p&gt;控制台输出这样的时候，很疑惑&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;:) select * from test
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;SELECT *
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;FROM test 
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;┌─s───┬───i─┐
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│ foo │ 123 │
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;└─────┴─────┘
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;┌─s───┬───i─┐
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│ bar │ 567 │
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;└─────┴─────┘
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;更快的写入是通过将数据写入多个分区来实现的，然后将数据离线合并到单个分区中以实现更快的读取&lt;&#x2F;p&gt;
&lt;p&gt;写入时会根据每次写入的批次或 &lt;code&gt;max_insert_block_size&lt;&#x2F;code&gt; （将大型写入拆分为单独的批次）&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;每次写入的批次
&lt;ul&gt;
&lt;li&gt;默认一条&lt;code&gt;insert&lt;&#x2F;code&gt;插入的数据为同一个数据分区，不同&lt;code&gt;insert&lt;&#x2F;code&gt;插入的数据为不同的分区&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;查询数据时往往是多线程查询，所有输入数据来自不同的分区，会由不同的线程的处理，命令行客户端在收到后立即打印&lt;&#x2F;p&gt;
&lt;p&gt;如果使用的查询不包含任何合并块的阻塞运算符（group by、order by 等），结果就会一一返回。&lt;&#x2F;p&gt;
&lt;p&gt;查看数据分区&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;var&#x2F;lib&#x2F;clickhouse&#x2F;data&#x2F;database_name&#x2F;table_name
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;optimize table {table_name}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;优化表会强制合并分区，数据现在在单个分区中&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;51899472&#x2F;clickhouse-split-output-on-select&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;55302833&#x2F;why-does-clickhouse-client-return-multiple-tables&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Arch | Docker没有runc</title>
          <pubDate>Sat, 12 Aug 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-08-12-arch-docker-no-runc/</link>
          <guid>https://inasa.dev/posts/23-08-12-arch-docker-no-runc/</guid>
          <description xml:base="https://inasa.dev/posts/23-08-12-arch-docker-no-runc/">&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;docker run -d -p 8080:8080 registry.cn-shanghai.aliyuncs.com&#x2F;akfamily&#x2F;aktools:1.8.95 python -m aktools --host 0.0.0.0 --port 8080
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;在运行上面命令后，报错&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: unable to retrieve OCI runtime error (open &#x2F;run&#x2F;containerd&#x2F;io.containerd.runtime.v2.task&#x2F;moby&#x2F;8ed2d74f98d4fdbdac68b67b1db6ac8c1d2537e99800fbc6c9243e1e94ef95dd&#x2F;log.json: no such file or directory): runc did not terminate successfully: exit status 1: unknown.
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;查了下是没有&lt;code&gt;runc&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;通过&lt;code&gt;docker version&lt;&#x2F;code&gt;查看，确实没有&lt;code&gt;runc&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;➜ docker version
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Client:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; Version:           24.0.5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; API version:       1.43
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; Go version:        go1.20.6
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; Git commit:        ced0996600
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; Built:             Wed Jul 26 21:44:58 2023
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; OS&#x2F;Arch:           linux&#x2F;amd64
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; Context:           default
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Server:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; Engine:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Version:          24.0.5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  API version:      1.43 (minimum version 1.12)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Go version:       go1.20.6
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Git commit:       a61e2b4c9c
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Built:            Wed Jul 26 21:44:58 2023
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  OS&#x2F;Arch:          linux&#x2F;amd64
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Experimental:     false
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; containerd:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Version:          v1.7.2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  GitCommit:        0cae528dd6cb557f7201036e9f43420650207b58.m
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; docker-init:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Version:          0.19.0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  GitCommit:        de40ad0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;安装&lt;code&gt;libseccomp&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;pacman -S libseccomp
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;重启&lt;code&gt;docker&lt;&#x2F;code&gt;后还是不行，但是尝试了下删除再安装，就可以了&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;➜ docker version
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Client:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; Version:           24.0.5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; API version:       1.43
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; Go version:        go1.20.6
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; Git commit:        ced0996600
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; Built:             Wed Jul 26 21:44:58 2023
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; OS&#x2F;Arch:           linux&#x2F;amd64
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; Context:           default
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Server:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; Engine:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Version:          24.0.5
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  API version:      1.43 (minimum version 1.12)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Go version:       go1.20.6
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Git commit:       a61e2b4c9c
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Built:            Wed Jul 26 21:44:58 2023
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  OS&#x2F;Arch:          linux&#x2F;amd64
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Experimental:     false
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; containerd:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Version:          v1.7.2
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  GitCommit:        0cae528dd6cb557f7201036e9f43420650207b58.m
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; runc:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Version:          1.1.9
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  GitCommit:        
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt; docker-init:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  Version:          0.19.0
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;  GitCommit:        de40ad0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</description>
      </item>
      <item>
          <title>Git | windows上遇到特殊字符的问题</title>
          <pubDate>Tue, 08 Aug 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-08-08-git-windows-special-char/</link>
          <guid>https://inasa.dev/posts/23-08-08-git-windows-special-char/</guid>
          <description xml:base="https://inasa.dev/posts/23-08-08-git-windows-special-char/">&lt;p&gt;参加了每日&lt;code&gt;CSAPP&lt;&#x2F;code&gt;阅读会，拉取https:&#x2F;&#x2F;github.com&#x2F;ArkTicketTech&#x2F;CSAPP-Everyday的时候&lt;&#x2F;p&gt;
&lt;p&gt;仓库里有文件和文件夹包含特殊字符&lt;code&gt;:&lt;&#x2F;code&gt;，只有在&lt;code&gt;windows&lt;&#x2F;code&gt;上行不通，好像还有其他特殊字符和保留字段，&lt;&#x2F;p&gt;
&lt;p&gt;直接&lt;code&gt;clone&lt;&#x2F;code&gt;的话，是行不通的&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ git clone https:&#x2F;&#x2F;github.com&#x2F;ArkTicketTech&#x2F;CSAPP-Everyday
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Cloning into &amp;#39;CSAPP-Everyday&amp;#39;...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote: Enumerating objects: 20600, done.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote: Counting objects: 100% (5084&#x2F;5084), done.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote: Compressing objects: 100% (2591&#x2F;2591), done.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote: Total 20600 (delta 2489), reused 4944 (delta 2398), pack-reused 15516
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Receiving objects: 100% (20600&#x2F;20600), 195.55 MiB | 4.72 MiB&#x2F;s, done.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Resolving deltas: 100% (9061&#x2F;9061), done.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;error: invalid path &amp;#39;homeworks&#x2F;2023&#x2F;2&#x2F;2&#x2F;holiday-2023:1:2&#x2F;holiday-2023:1:2.md&amp;#39;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;fatal: unable to checkout working tree
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;warning: Clone succeeded, but checkout failed.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;You can inspect what was checked out with &amp;#39;git status&amp;#39;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;and retry with &amp;#39;git restore --source=HEAD :&#x2F;&amp;#39;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;git&lt;&#x2F;code&gt;会自动把所有文件删除（除了&lt;code&gt;.git&lt;&#x2F;code&gt;），放入暂存区&lt;&#x2F;p&gt;
&lt;p&gt;问了大佬，尝试把这几个特殊文件放入&lt;code&gt;.gitignore&lt;&#x2F;code&gt;中&lt;&#x2F;p&gt;
&lt;p&gt;把其余文件&lt;code&gt;restore&lt;&#x2F;code&gt;后，特殊文件一直保留在暂存区，看着很不爽，有两个问题&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;如果不小心把特殊文件提交，那么&lt;code&gt;reset&lt;&#x2F;code&gt;也不管用，会一直报&lt;code&gt;invalid path&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;如果一直忽略，当再次&lt;code&gt;pull&lt;&#x2F;code&gt;时，会遇到奇怪的问题，特殊文件从暂存区消失，会替换为另外两个正常的文件，且这两个文件不能被&lt;code&gt;restore&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;image&#x2F;git-windows-invalid-path&#x2F;1.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;image&#x2F;git-windows-invalid-path&#x2F;2.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;决定再次尝试一下sparse，看了官方文档https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-sparse-checkout，成功了&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Inasa@Inasa-Windows11 MINGW64 ~&#x2F;Desktop&#x2F;tmp1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ git clone --sparse -c core.protectNTFS=false -n https:&#x2F;&#x2F;github.com&#x2F;ArkTicketTech&#x2F;CSAPP-Everyday.git
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Cloning into &amp;#39;CSAPP-Everyday&amp;#39;...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote: Enumerating objects: 20600, done.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote: Counting objects: 100% (5084&#x2F;5084), done.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote: Compressing objects: 100% (2592&#x2F;2592), done.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;remote: Total 20600 (delta 2488), reused 4944 (delta 2397), pack-reused 15516Receiving objects: 100% (20600&#x2F;20600), 193.77 MiB | 7.55 MiB&#x2F;s
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Receiving objects: 100% (20600&#x2F;20600), 195.55 MiB | 7.46 MiB&#x2F;s, done.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Resolving deltas: 100% (9058&#x2F;9058), done.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Inasa@Inasa-Windows11 MINGW64 ~&#x2F;Desktop&#x2F;tmp1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$  git sparse-checkout set --no-cone &amp;#39;&#x2F;*&amp;#39; &amp;#39;!homeworks&#x2F;2023&#x2F;2&#x2F;2&#x2F;*&amp;#39;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;fatal: not a git repository (or any of the parent directories): .git
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Inasa@Inasa-Windows11 MINGW64 ~&#x2F;Desktop&#x2F;tmp1
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ cd CSAPP-Everyday&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Inasa@Inasa-Windows11 MINGW64 ~&#x2F;Desktop&#x2F;tmp1&#x2F;CSAPP-Everyday (main|SPARSE)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$  git sparse-checkout set --no-cone &amp;#39;&#x2F;*&amp;#39; &amp;#39;!homeworks&#x2F;2023&#x2F;2&#x2F;2&#x2F;*&amp;#39;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Inasa@Inasa-Windows11 MINGW64 ~&#x2F;Desktop&#x2F;tmp1&#x2F;CSAPP-Everyday (main|SPARSE)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ git sparse-checkout list
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;&#x2F;*
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;!homeworks&#x2F;2023&#x2F;2&#x2F;2&#x2F;*
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Inasa@Inasa-Windows11 MINGW64 ~&#x2F;Desktop&#x2F;tmp1&#x2F;CSAPP-Everyday (main|SPARSE)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ git checkout main
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Updating files: 100% (4428&#x2F;4428), done.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Already on &amp;#39;main&amp;#39;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Your branch is up to date with &amp;#39;origin&#x2F;main&amp;#39;.
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;Inasa@Inasa-Windows11 MINGW64 ~&#x2F;Desktop&#x2F;tmp1&#x2F;CSAPP-Everyday (main|SPARSE)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;$ ls
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;checkin.py  create.sh  homeworks&#x2F;  LICENSE  package.json  package-lock.json  readers.txt  README.md  textbooks&#x2F;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;inasa.dev&#x2F;image&#x2F;git-windows-invalid-path&#x2F;3.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-sparse-checkout&lt;&#x2F;li&gt;
&lt;li&gt;OPENAI&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;63727594&#x2F;github-git-checkout-returns-error-invalid-path-on-windows&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;github.com&#x2F;bcgov&#x2F;wps&#x2F;issues&#x2F;2605&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;61614004&#x2F;cloning-succeded-but-checkout-failed-due-to-invalid-path-what-is-the-path-probl&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;14326365&#x2F;git-clone-ignoring-a-directory&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Go | 使一个结构体类型不可比较</title>
          <pubDate>Tue, 08 Aug 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-08-08-go-make-struct-not-compare/</link>
          <guid>https://inasa.dev/posts/23-08-08-go-make-struct-not-compare/</guid>
          <description xml:base="https://inasa.dev/posts/23-08-08-go-make-struct-not-compare/">&lt;p&gt;可以放置一个非导出的零尺寸的不可比较类型的字段在结构体类型中以使此结构体类型不可比较&lt;&#x2F;p&gt;
&lt;p&gt;结构体&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;type T struct {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	dummy [0]func()
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	AnotherField int
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;使用&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;var x map[T]int &#x2F;&#x2F; 编译错误：非法的键值类型
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;var a, b T
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;_ = a == b &#x2F;&#x2F; 编译错误：非法的比较
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</description>
      </item>
      <item>
          <title>Make | 在target中使用条件语句</title>
          <pubDate>Tue, 08 Aug 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-08-08-make-target/</link>
          <guid>https://inasa.dev/posts/23-08-08-make-target/</guid>
          <description xml:base="https://inasa.dev/posts/23-08-08-make-target/">&lt;p&gt;之前一直是&lt;code&gt;target&lt;&#x2F;code&gt;换行后缩进，是不对的&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;target:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    ifeq (foo, bar)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;        ...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    endif
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;但条件语句应该不缩进编写&lt;&#x2F;p&gt;
&lt;p&gt;如果没有缩进，&lt;code&gt;Make&lt;&#x2F;code&gt; 会将其视为自己的指令；否则，它将被视为 &lt;code&gt;shell&lt;&#x2F;code&gt; 脚本。&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;target:
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;ifeq (foo, bar)
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;    ...
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;endif
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;正确的&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;4483313&#x2F;make-error-for-ifeq-syntax-error-near-unexpected-token&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Go | 0尺寸结构体</title>
          <pubDate>Mon, 07 Aug 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-08-07-go-zero-struct/</link>
          <guid>https://inasa.dev/posts/23-08-07-go-zero-struct/</guid>
          <description xml:base="https://inasa.dev/posts/23-08-07-go-zero-struct/">&lt;p&gt;下面四个结构体的尺寸大小各是多少？&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;type A struct {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	x int64
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	y int64
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;type A1 struct {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	x int64
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	y int64
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	z struct{}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;type A2 struct {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	z struct{}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	x int64
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	y int64
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;type A3 struct {
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	x int64
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	z struct{}
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;	y int64
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;答案&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;A： 16
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;A1： 24
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;A2： 16
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;A3： 16
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;为什么A1的结构体会不同呢？&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;一个可寻址的结构值的所有字段都可以被取地址，A1可以被取地址，则z也可以被取地址&lt;&#x2F;li&gt;
&lt;li&gt;如果非零尺寸的结构体值的最后一个字段的尺寸是零，那么取此最后一个字段的地址将会返回一个越出了结构体值分配的内存块的地址（可能指向另一个被分配的内存块）&lt;&#x2F;li&gt;
&lt;li&gt;标准的Go编译器会确保取一个非零尺寸的结构体值的最后一个字段的地址时，绝对不会返回越出分配给此结构体值的内存块的地址&lt;&#x2F;li&gt;
&lt;li&gt;Go标准编译器通过在需要时在结构体最后的零尺寸字段之后填充一些字节来实现这一点
&lt;ul&gt;
&lt;li&gt;具体补多少，需要达到内存对齐即可&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;如果一个结构体的全部字段的类型都是零尺寸的(因此整个结构体也是零尺寸的)，那么就不需要再填充字节，因为标准编译器会专门处理零尺寸的内存块&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;Golang101&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Arch | AUR镜像源连接超时</title>
          <pubDate>Thu, 27 Jul 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-07-27-arch-aur-timeout/</link>
          <guid>https://inasa.dev/posts/23-07-27-arch-aur-timeout/</guid>
          <description xml:base="https://inasa.dev/posts/23-07-27-arch-aur-timeout/">&lt;p&gt;对很多人来说，Chaotic-AUR（我们的资源库）的下载速度一直都很糟糕。原因很简单： 很多人都不会更改 Chaotic 镜像列表的默认顺序，因为它不受 Reflector（Arch 镜像列表图形用户界面）的影响，这导致每个人都从同一个服务器下载。更新后的镜像列表包括自动地理镜像和 CDN 镜像，它们都有助于分散负载。&lt;&#x2F;p&gt;
&lt;p&gt;编辑&lt;code&gt;chaotic-mirrorlist&lt;&#x2F;code&gt;文件&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;vim &#x2F;etc&#x2F;pacman.d&#x2F;chaotic-mirrorlist
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;然后注释出要使用的镜像前的所有镜像--最好选择离您最近的镜像。最后，使用新镜像刷新数据库并更新。&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;sudo pacman -Syu
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;zhuanlan.zhihu.com&#x2F;p&#x2F;575684535?utm_id=0&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;wiki.garudalinux.org&#x2F;en&#x2F;increasing-download-speed&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Arch | AUR仓库使用记录</title>
          <pubDate>Thu, 27 Jul 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-07-27-arch-how-to-use-aur/</link>
          <guid>https://inasa.dev/posts/23-07-27-arch-how-to-use-aur/</guid>
          <description xml:base="https://inasa.dev/posts/23-07-27-arch-how-to-use-aur/">&lt;p&gt;Arch User Repository (AUR) 是一个由社区驱动的软件存储库，可用于在 Arch Linux 和衍生操作系统上安装软件。AUR 包含以 PKGBUILD 形式提供的软件包描述，这些描述允许您使用 makepkg 从源代码构建软件包，然后使用 pacman 安装。&lt;&#x2F;p&gt;
&lt;p&gt;尽管clickhouse提供了&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;clickhouse.com&#x2F;docs&#x2F;en&#x2F;install#from-tgz-archives&quot;&gt;From Tgz Archives&lt;&#x2F;a&gt;的安装方式&lt;&#x2F;p&gt;
&lt;p&gt;在AUR找到地址https:&#x2F;&#x2F;aur.archlinux.org&#x2F;packages&#x2F;clickhouse&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;git clone https:&#x2F;&#x2F;aur.archlinux.org&#x2F;clickhouse.git
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;cd clickhouse
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;makepkg
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;执行完成之后会出现以&lt;code&gt;pkg.tar.zst&lt;&#x2F;code&gt;为结尾的文件，这就是打包的文件，可以直接用&lt;code&gt;pacman&lt;&#x2F;code&gt;安装&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;pacman -U clickhouse-23.6.2.18-1-x86_64.pkg.tar.zst
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;wiki.archlinux.org&#x2F;title&#x2F;Arch_User_Repository&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;aur.archlinux.org&#x2F;packages&#x2F;clickhouse&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;clickhouse.com&#x2F;docs&#x2F;en&#x2F;install&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Go | PGO翻译</title>
          <pubDate>Fri, 30 Jun 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-06-30-go-pgo-translate/</link>
          <guid>https://inasa.dev/posts/23-06-30-go-pgo-translate/</guid>
          <description xml:base="https://inasa.dev/posts/23-06-30-go-pgo-translate/">&lt;p&gt;从&lt;code&gt;Go 1.20&lt;&#x2F;code&gt;开始，&lt;code&gt;Go&lt;&#x2F;code&gt;编译器支持配置文件引导的优化（&lt;code&gt;PGO&lt;&#x2F;code&gt;），以进一步优化构建。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;overview&quot;&gt;Overview&lt;a class=&quot;zola-anchor&quot; href=&quot;#overview&quot; aria-label=&quot;Anchor link for: overview&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;code&gt;Profile-guided optimization&lt;&#x2F;code&gt;（配置文件指导下的优化）（PGO），也被称为 &lt;code&gt;feedback-directed optimization&lt;&#x2F;code&gt; （反馈指导下的优化）（FDO），是一种编译器优化技术，它将应用程序的代表性运行信息（配置文件）反馈给编译器，用于应用程序的下一次构建，编译器利用这些信息做出更明智的优化决定。例如，编译器可以决定更积极地内联那些概况显示经常被调用的函数。&lt;&#x2F;p&gt;
&lt;p&gt;在&lt;code&gt;Go&lt;&#x2F;code&gt;中，编译器使用&lt;code&gt;CPU pprof&lt;&#x2F;code&gt;配置文件作为输入配置文件，例如来自&lt;code&gt;runtime&#x2F;pprof&lt;&#x2F;code&gt;或&lt;code&gt;net&#x2F;http&#x2F;pprof&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;截至&lt;code&gt;Go 1.21&lt;&#x2F;code&gt;，一组有代表性的&lt;code&gt;Go&lt;&#x2F;code&gt;程序的基准测试显示，使用&lt;code&gt;PGO&lt;&#x2F;code&gt;构建程序可以提高约2-7%的性能。我们预计，随着更多的优化措施在未来的&lt;code&gt;Go&lt;&#x2F;code&gt;版本中利用&lt;code&gt;PGO&lt;&#x2F;code&gt;，性能的提高会随着时间的推移而普遍增加。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;collecting-profiles&quot;&gt;Collecting profiles&lt;a class=&quot;zola-anchor&quot; href=&quot;#collecting-profiles&quot; aria-label=&quot;Anchor link for: collecting-profiles&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;code&gt;Go&lt;&#x2F;code&gt;编译器希望&lt;code&gt;CPU pprof&lt;&#x2F;code&gt;配置文件作为&lt;code&gt;PGO&lt;&#x2F;code&gt;的输入。&lt;code&gt;Go&lt;&#x2F;code&gt;运行时生成的配置文件（例如来自运行时&lt;code&gt;runtime&#x2F;pprof&lt;&#x2F;code&gt;和&lt;code&gt;net&#x2F;http&#x2F;pprof&lt;&#x2F;code&gt;）可以直接作为编译器的输入。也可以使用&#x2F;转换其他剖析系统的配置文件。&lt;&#x2F;p&gt;
&lt;p&gt;为了获得最佳效果，配置文件必须代表应用程序生产环境中的实际行为。使用不具代表性的配置文件可能会导致二进制文件在生产中几乎没有任何改进。因此，建议直接从生产环境中收集配置文件，这也是 &lt;code&gt;Go&lt;&#x2F;code&gt; 的 &lt;code&gt;PGO&lt;&#x2F;code&gt; 所设计的主要方法。&lt;&#x2F;p&gt;
&lt;p&gt;典型的工作流程如下：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;构建并发布初始二进制文件（不含 PGO）&lt;&#x2F;li&gt;
&lt;li&gt;从生产中收集配置文件&lt;&#x2F;li&gt;
&lt;li&gt;当需要发布更新的二进制文件时，从最新的源代码构建并提供生产配置文件&lt;&#x2F;li&gt;
&lt;li&gt;GOTO 2&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;code&gt;Go PGO&lt;&#x2F;code&gt; 对于应用程序的剖析版本和使用剖析文件构建的版本之间的偏差，以及使用从已优化的二进制文件中收集的剖析文件进行构建，一般都很稳健。这也是使这个迭代生命周期成为可能的原因。关于这个工作流程的其他细节，请参见&lt;code&gt;AutoFDO&lt;&#x2F;code&gt;部分。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;building-with-pgo&quot;&gt;Building with PGO&lt;a class=&quot;zola-anchor&quot; href=&quot;#building-with-pgo&quot; aria-label=&quot;Anchor link for: building-with-pgo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;标准的构建方法是将文件名为&lt;code&gt;default.pgo&lt;&#x2F;code&gt;的&lt;code&gt;pprof&lt;&#x2F;code&gt; &lt;code&gt;CPU&lt;&#x2F;code&gt;配置文件存储在被剖析二进制文件的主包目录中。默认情况下，&lt;code&gt;go build&lt;&#x2F;code&gt;会自动检测&lt;code&gt;default.pgo&lt;&#x2F;code&gt;文件并启用&lt;code&gt;PGO&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;推荐在源码库中直接提交配置文件，因为配置文件是构建的重要输入，对于可重复性（和性能！）的构建非常重要。与源码一起存储可以简化构建体验，因为除了获取源码之外，没有其他步骤可以获得配置文件。&lt;&#x2F;p&gt;
&lt;p&gt;对于更复杂的情况，&lt;code&gt;go build -pgo&lt;&#x2F;code&gt;标志控制&lt;code&gt;PGO&lt;&#x2F;code&gt;配置文件的选择。这个标志的默认值是&lt;code&gt;-pgo=auto&lt;&#x2F;code&gt;，即上述的默认&lt;code&gt;.pgo&lt;&#x2F;code&gt;行为。将该标志设置为&lt;code&gt;-pgo=off&lt;&#x2F;code&gt;则完全禁用&lt;code&gt;PGO&lt;&#x2F;code&gt;优化。&lt;&#x2F;p&gt;
&lt;p&gt;如果你不能使用&lt;code&gt;default.pgo&lt;&#x2F;code&gt;（例如，一个二进制文件的不同场景需要不同的配置文件，无法将配置文件与源代码一起存储，等等），你可以直接传递一个要使用的配置文件的路径（例如，&lt;code&gt;go build -pgo=&#x2F;tmp&#x2F;foo.prof&lt;&#x2F;code&gt;）。&lt;&#x2F;p&gt;
&lt;p&gt;例如，&lt;code&gt;go build -pgo=&#x2F;tmp&#x2F;foo.prof .&#x2F;cmd&#x2F;foo .&#x2F;cmd&#x2F;bar&lt;&#x2F;code&gt;将&lt;code&gt;foo.prof&lt;&#x2F;code&gt;应用于二进制文件&lt;code&gt;foo&lt;&#x2F;code&gt;和&lt;code&gt;bar&lt;&#x2F;code&gt;，这往往不是你想要的。通常，不同的二进制文件应该有不同的配置文件，通过单独的&lt;code&gt;go build&lt;&#x2F;code&gt;调用传递。&lt;&#x2F;p&gt;
&lt;p&gt;注意：在&lt;code&gt;Go 1.21&lt;&#x2F;code&gt;之前，默认是&lt;code&gt;-pgo=off&lt;&#x2F;code&gt;。必须明确启用&lt;code&gt;PGO&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;notes&quot;&gt;Notes&lt;a class=&quot;zola-anchor&quot; href=&quot;#notes&quot; aria-label=&quot;Anchor link for: notes&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;h4 id=&quot;cong-sheng-chan-zhong-shou-ji-dai-biao-xing-zi-liao&quot;&gt;从生产中收集代表性资料&lt;a class=&quot;zola-anchor&quot; href=&quot;#cong-sheng-chan-zhong-shou-ji-dai-biao-xing-zi-liao&quot; aria-label=&quot;Anchor link for: cong-sheng-chan-zhong-shou-ji-dai-biao-xing-zi-liao&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;你的生产环境是你的应用程序有代表性的配置文件的最佳来源，如收集配置文件中所述。&lt;&#x2F;p&gt;
&lt;p&gt;最简单的方法是将 &lt;code&gt;net&#x2F;http&#x2F;pprof&lt;&#x2F;code&gt; 添加到你的应用程序中，然后从你的服务的任意实例中获取 &lt;code&gt;&#x2F;debug&#x2F;pprof&#x2F;profile?seconds=30&lt;&#x2F;code&gt;。这是一个很好的入门方法，但也有一些方法可能不具代表性：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;这个实例在被剖析的时候可能没有做任何事情，尽管它通常很忙。&lt;&#x2F;li&gt;
&lt;li&gt;流量模式可能会在一天中发生变化，从而导致行为在一天中发生变化。&lt;&#x2F;li&gt;
&lt;li&gt;实例可能会执行长期运行的操作（例如，5分钟做操作A，然后5分钟做操作B，等等）。一个30秒的配置文件可能只涵盖一个单一的操作类型。&lt;&#x2F;li&gt;
&lt;li&gt;实例可能没有收到公平的请求分布（一些实例比其他实例收到更多的一种类型的请求）。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;一个更稳健的策略是在不同的时间从不同的实例收集多个配置文件，以限制单个实例配置文件之间的差异的影响。然后可以将多个配置文件合并为一个配置文件，供&lt;code&gt;PGO&lt;&#x2F;code&gt;使用。&lt;&#x2F;p&gt;
&lt;p&gt;许多组织都在运行 &quot;连续剖析 &quot;服务，自动进行这种车队范围内的采样剖析，然后可以作为&lt;code&gt;PGO&lt;&#x2F;code&gt;的剖析来源。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;he-bing-pei-zhi-wen-jian&quot;&gt;合并配置文件&lt;a class=&quot;zola-anchor&quot; href=&quot;#he-bing-pei-zhi-wen-jian&quot; aria-label=&quot;Anchor link for: he-bing-pei-zhi-wen-jian&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;code&gt;pprof&lt;&#x2F;code&gt; 工具可以合并多个配置文件，如下所示：&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;go tool pprof -proto a.pprof b.pprof &amp;gt; merged.pprof
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这种合并实际上是输入中样本的简单求和，无论配置文件的墙持续时间如何。因此，在分析应用程序的小时间片（例如，无限期运行的服务器）时，您可能希望确保所有配置文件具有相同的墙持续时间（即，收集所有配置文件 30 秒）。否则，具有较长墙持续时间的配置文件将在合并的配置文件中过多表示。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;autofdo&quot;&gt;AutoFDO&lt;a class=&quot;zola-anchor&quot; href=&quot;#autofdo&quot; aria-label=&quot;Anchor link for: autofdo&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;Go PGO&lt;&#x2F;code&gt; 旨在支持“&lt;code&gt;AutoFDO&lt;&#x2F;code&gt;”风格的工作流程。&lt;&#x2F;p&gt;
&lt;p&gt;让我们仔细看看收集资料中描述的工作流程：&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;构建并发布初始二进制文件（不含 &lt;code&gt;PGO&lt;&#x2F;code&gt;）&lt;&#x2F;li&gt;
&lt;li&gt;从生产中收集配置文件&lt;&#x2F;li&gt;
&lt;li&gt;当需要发布更新的二进制文件时，从最新的源代码构建并提供生产配置文件&lt;&#x2F;li&gt;
&lt;li&gt;GOTO 2&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;这听起来很简单，但这里有几个重要的属性需要注意：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;开发始终是持续的，所以二进制的剖析版本的源代码（步骤2）可能与正在构建的最新源代码（步骤3）略有不同。&lt;code&gt;Go PGO&lt;&#x2F;code&gt;的设计是为了适应这种情况，我们称之为源代码的稳定性。&lt;&#x2F;li&gt;
&lt;li&gt;这是一个闭环。也就是说，在第一次迭代之后，二进制文件的剖析版本已经通过前一次迭代的剖析进行了PGO优化。&lt;code&gt;Go PGO&lt;&#x2F;code&gt;也被设计为对这种情况具有鲁棒性，我们称之为迭代稳定性。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;yuan-wen-ding-xing-he-zhong-gou&quot;&gt;源稳定性和重构&lt;a class=&quot;zola-anchor&quot; href=&quot;#yuan-wen-ding-xing-he-zhong-gou&quot; aria-label=&quot;Anchor link for: yuan-wen-ding-xing-he-zhong-gou&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;如上所述，&lt;code&gt;Go&lt;&#x2F;code&gt;的&lt;code&gt;PGO&lt;&#x2F;code&gt;尽最大努力尝试继续将旧的配置文件中的样本与当前的源代码进行匹配。具体来说，&lt;code&gt;Go&lt;&#x2F;code&gt;使用函数内的行偏移量（例如，在函数&lt;code&gt;foo&lt;&#x2F;code&gt;的第5行调用）。&lt;&#x2F;p&gt;
&lt;p&gt;许多常见的更改不会破坏匹配，包括：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;在热函数之外更改文件（在函数上方或下方添加&#x2F;更改代码）&lt;&#x2F;li&gt;
&lt;li&gt;将函数移动到同一包中的另一个文件（编译器完全忽略源文件名）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;一些可能会破坏匹配的更改：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;热函数内的更改（可能会影响行偏移）&lt;&#x2F;li&gt;
&lt;li&gt;重命名函数（和&#x2F;或方法的类型）（更改符号名称）&lt;&#x2F;li&gt;
&lt;li&gt;将函数移动到另一个包（更改符号名称）&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;xin-dai-ma-de-xing-neng&quot;&gt;新代码的性能&lt;a class=&quot;zola-anchor&quot; href=&quot;#xin-dai-ma-de-xing-neng&quot; aria-label=&quot;Anchor link for: xin-dai-ma-de-xing-neng&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;当添加新的代码或通过翻转标志启用新的代码路径时，该代码在第一次构建时不会出现在配置文件中，因此在收集到反映新代码的新配置文件之前，不会得到&lt;code&gt;PGO&lt;&#x2F;code&gt;优化。在评估新代码的推出时，请记住，初始版本并不代表其稳定状态的性能。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;go.dev&#x2F;doc&#x2F;pgo&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;oilbeater.com&#x2F;2023&#x2F;06&#x2F;24&#x2F;optimization-without-changing-code-pgo&#x2F;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Rust | Ownership</title>
          <pubDate>Tue, 20 Jun 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-06-20-rust-ownership/</link>
          <guid>https://inasa.dev/posts/23-06-20-rust-ownership/</guid>
          <description xml:base="https://inasa.dev/posts/23-06-20-rust-ownership/">&lt;h2 id=&quot;yi-duan-bu-an-quan-de-dai-ma&quot;&gt;一段不安全的代码&lt;a class=&quot;zola-anchor&quot; href=&quot;#yi-duan-bu-an-quan-de-dai-ma&quot; aria-label=&quot;Anchor link for: yi-duan-bu-an-quan-de-dai-ma&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;c&quot; class=&quot;language-c z-code&quot;&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-c&quot;&gt;foo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-c&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-parameters z-c&quot;&gt;&lt;span class=&quot;z-meta z-group z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-c&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-c&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;int&lt;&#x2F;span&gt; a&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;          &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 变量a的作用域开始
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    a &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-c&quot;&gt;100&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-storage z-type z-c&quot;&gt;char&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;*&lt;&#x2F;span&gt;c &lt;span class=&quot;z-keyword z-operator z-assignment z-c&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;xyz&lt;span class=&quot;z-punctuation z-definition z-string z-end z-c&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;   &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 变量c的作用域开始
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;    &lt;span class=&quot;z-keyword z-control z-flow z-return z-c&quot;&gt;return&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-c&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;a&lt;span class=&quot;z-punctuation z-terminator z-c&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-c&quot;&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-c&quot;&gt;&lt;span class=&quot;z-meta z-block z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-c&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;                   &lt;span class=&quot;z-comment z-line z-double-slash z-c&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-c&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 变量a和c的作用域结束
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;变量 &lt;code&gt;a&lt;&#x2F;code&gt; 和 &lt;code&gt;c&lt;&#x2F;code&gt; 都是局部变量，函数结束后将局部变量 &lt;code&gt;a&lt;&#x2F;code&gt; 的地址返回，但局部变量 &lt;code&gt;a&lt;&#x2F;code&gt; 存在栈中，在离开作用域后，&lt;code&gt;a&lt;&#x2F;code&gt; 所申请的栈上内存都会被系统回收，从而造成了 &lt;code&gt;悬空指针(Dangling Pointer)&lt;&#x2F;code&gt; 的问题。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;​		虽然编译可以通过，但是运行的时候会出现错误。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;变量 &lt;code&gt;c&lt;&#x2F;code&gt;常量字符串，存储于常量区， &lt;code&gt;&quot;xyz&quot;&lt;&#x2F;code&gt; 只有当整个程序结束后系统才能回收这片内存。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;zhan-stack-yu-dui-heap&quot;&gt;栈(Stack)与堆(Heap)&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhan-stack-yu-dui-heap&quot; aria-label=&quot;Anchor link for: zhan-stack-yu-dui-heap&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;栈中的所有数据都必须占用已知且固定大小的内存空间&lt;&#x2F;li&gt;
&lt;li&gt;对于大小未知或者可能变化的数据，需要存储在堆上
&lt;ul&gt;
&lt;li&gt;当向堆上放入数据时，需要请求一定大小的内存空间。操作系统在堆的某处找到一块足够大的空位，把它标记为已使用，并返回一个表示该位置地址的&lt;strong&gt;指针&lt;&#x2F;strong&gt;, 该过程被称为&lt;strong&gt;在堆上分配内存&lt;&#x2F;strong&gt;，有时简称为 “分配”(&lt;code&gt;allocating&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;接着，该指针会被推入&lt;strong&gt;栈&lt;&#x2F;strong&gt;中，因为指针的大小是已知且固定的，在后续使用过程中，你将通过栈中的&lt;strong&gt;指针&lt;&#x2F;strong&gt;，来获取数据在堆上的实际内存位置，进而访问该数据&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;写入
&lt;ul&gt;
&lt;li&gt;入栈比在堆上分配内存要快&lt;&#x2F;li&gt;
&lt;li&gt;入栈时操作系统无需分配新的空间，只需要将新数据放入栈顶即可&lt;&#x2F;li&gt;
&lt;li&gt;在堆上分配内存则需要更多的工作，这是因为操作系统必须首先找到一块足够存放数据的内存空间，接着做一些记录为下一次分配做准备&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;读取
&lt;ul&gt;
&lt;li&gt;得益于 CPU 高速缓存，使得处理器可以减少对内存的访问，高速缓存和内存的访问速度差异在 10 倍以上&lt;&#x2F;li&gt;
&lt;li&gt;栈数据往往可以直接存储在 CPU 高速缓存中，而堆数据只能存储在内存中&lt;&#x2F;li&gt;
&lt;li&gt;访问堆上的数据比访问栈上的数据慢，因为必须先访问栈再通过栈上的指针来访问内存&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;suo-you-quan-yuan-ze&quot;&gt;所有权原则&lt;a class=&quot;zola-anchor&quot; href=&quot;#suo-you-quan-yuan-ze&quot; aria-label=&quot;Anchor link for: suo-you-quan-yuan-ze&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;Rust 中每一个值都被一个变量所拥有，该变量被称为值的所有者&lt;&#x2F;li&gt;
&lt;li&gt;一个值同时只能被一个变量所拥有，或者说一个值只能拥有一个所有者&lt;&#x2F;li&gt;
&lt;li&gt;当所有者(变量)离开作用域范围时，这个值将被丢弃(drop)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;bian-liang-bang-ding-bei-hou-de-shu-ju-jiao-hu&quot;&gt;变量绑定背后的数据交互&lt;a class=&quot;zola-anchor&quot; href=&quot;#bian-liang-bang-ding-bei-hou-de-shu-ju-jiao-hu&quot; aria-label=&quot;Anchor link for: bian-liang-bang-ding-bei-hou-de-shu-ju-jiao-hu&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h4 id=&quot;zhuan-yi-suo-you-quan&quot;&gt;转移所有权&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhuan-yi-suo-you-quan&quot; aria-label=&quot;Anchor link for: zhuan-yi-suo-you-quan&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; x &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; y &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; x&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;两个值都是通过自动拷贝的方式来赋值的，都被存在栈中，完全无需在堆上分配内存&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; s1 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-rust&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;from&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; s2 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; s1&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;对于基本类型（存储在栈上），Rust 会自动拷贝，但是 &lt;code&gt;String&lt;&#x2F;code&gt; 不是基本类型，而且是存储在堆上的，因此不能自动拷贝。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;String&lt;&#x2F;code&gt; 类型是一个复杂类型，由&lt;strong&gt;存储在栈中的堆指针&lt;&#x2F;strong&gt;、&lt;strong&gt;字符串长度&lt;&#x2F;strong&gt;、&lt;strong&gt;字符串容量&lt;&#x2F;strong&gt;共同组成，其中&lt;strong&gt;堆指针&lt;&#x2F;strong&gt;是最重要的，它指向了真实存储字符串内容的堆内存，至于长度和容量，如果你有 Go 语言的经验，这里就很好理解：容量是堆内存分配空间的大小，长度是目前已经使用的大小。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;String&lt;&#x2F;code&gt; 类型指向了一个堆上的空间，这里存储着它的真实数据, 下面对上面代码中的 &lt;code&gt;let s2 = s1&lt;&#x2F;code&gt; 分成两种情况讨论：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;拷贝 &lt;code&gt;String&lt;&#x2F;code&gt; 和存储在堆上的字节数组 如果该语句是拷贝所有数据(深拷贝)，那么无论是 &lt;code&gt;String&lt;&#x2F;code&gt; 本身还是底层的堆上数据，都会被全部拷贝，这对于性能而言会造成非常大的影响&lt;&#x2F;li&gt;
&lt;li&gt;只拷贝 &lt;code&gt;String&lt;&#x2F;code&gt; 本身 这样的拷贝非常快，因为在 64 位机器上就拷贝了 &lt;code&gt;8字节的指针&lt;&#x2F;code&gt;、&lt;code&gt;8字节的长度&lt;&#x2F;code&gt;、&lt;code&gt;8字节的容量&lt;&#x2F;code&gt;，总计 24 字节，但是带来了新的问题：&lt;strong&gt;一个值只允许有一个所有者&lt;&#x2F;strong&gt;，而现在这个值（堆上的真实字符串数据）有了两个所有者：&lt;code&gt;s1&lt;&#x2F;code&gt; 和 &lt;code&gt;s2&lt;&#x2F;code&gt;。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;当变量离开作用域后，Rust 会自动调用 &lt;code&gt;drop&lt;&#x2F;code&gt; 函数并清理变量的堆内存。&lt;&#x2F;p&gt;
&lt;p&gt;当 &lt;code&gt;s1&lt;&#x2F;code&gt; 和 &lt;code&gt;s2&lt;&#x2F;code&gt; 离开作用域，它们都会尝试释放相同的内存。这是一个叫做 &lt;strong&gt;二次释放（double free）&lt;&#x2F;strong&gt; 的错误。&lt;&#x2F;p&gt;
&lt;p&gt;所以，Rust 这样解决问题：&lt;strong&gt;当 &lt;code&gt;s1&lt;&#x2F;code&gt; 赋予 &lt;code&gt;s2&lt;&#x2F;code&gt; 后，Rust 认为 &lt;code&gt;s1&lt;&#x2F;code&gt; 不再有效，因此也无需在 &lt;code&gt;s1&lt;&#x2F;code&gt; 离开作用域后 &lt;code&gt;drop&lt;&#x2F;code&gt; 任何东西，这就是把所有权从 &lt;code&gt;s1&lt;&#x2F;code&gt; 转移给了 &lt;code&gt;s2&lt;&#x2F;code&gt;，&lt;code&gt;s1&lt;&#x2F;code&gt; 在被赋予 &lt;code&gt;s2&lt;&#x2F;code&gt; 后就马上失效了&lt;&#x2F;strong&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;看看在所有权转移后再来使用旧的所有者&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;let s1 = String::from(&amp;quot;hello&amp;quot;);
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;let s2 = s1;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;println!(&amp;quot;{}, world!&amp;quot;, s1);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Rust 会禁止你使用无效的引用&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; x&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;str&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;hello, world&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; y &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; x&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;&#x2F;span&gt;,&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt;y&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;x&lt;&#x2F;code&gt; 只是引用了存储在二进制中的字符串 &lt;code&gt;&quot;hello, world&quot;&lt;&#x2F;code&gt;，并没有持有所有权。&lt;&#x2F;p&gt;
&lt;p&gt;因此 &lt;code&gt;let y = x&lt;&#x2F;code&gt; 中，仅仅是对该引用进行了拷贝，此时 &lt;code&gt;y&lt;&#x2F;code&gt; 和 &lt;code&gt;x&lt;&#x2F;code&gt; 都引用了同一个字符串。&lt;&#x2F;p&gt;
&lt;h4 id=&quot;ke-long-shen-kao-bei&quot;&gt;克隆(深拷贝)&lt;a class=&quot;zola-anchor&quot; href=&quot;#ke-long-shen-kao-bei&quot; aria-label=&quot;Anchor link for: ke-long-shen-kao-bei&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;strong&gt;Rust 永远也不会自动创建数据的 “深拷贝”&lt;&#x2F;strong&gt;。任何&lt;strong&gt;自动&lt;&#x2F;strong&gt;的复制都不是深拷贝。&lt;&#x2F;p&gt;
&lt;p&gt;如果&lt;strong&gt;确实&lt;&#x2F;strong&gt;需要深度复制 &lt;code&gt;String&lt;&#x2F;code&gt; 中堆上的数据，而不仅仅是栈上的数据，可以使用一个叫做 &lt;code&gt;clone&lt;&#x2F;code&gt; 的方法。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; s1 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-rust&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;from&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; s2 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; s1&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;clone&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;s1 = &lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;&#x2F;span&gt;, s2 = &lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; s1&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; s2&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;s2&lt;&#x2F;code&gt; 完整的复制了 &lt;code&gt;s1&lt;&#x2F;code&gt; 的数据&lt;&#x2F;p&gt;
&lt;h4 id=&quot;kao-bei-qian-kao-bei&quot;&gt;拷贝(浅拷贝)&lt;a class=&quot;zola-anchor&quot; href=&quot;#kao-bei-qian-kao-bei&quot; aria-label=&quot;Anchor link for: kao-bei-qian-kao-bei&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;浅拷贝只发生在栈上&lt;&#x2F;p&gt;
&lt;p&gt;Rust 有一个叫做 &lt;code&gt;Copy&lt;&#x2F;code&gt; 的特征，可以用在类似整型这样在栈中存储的类型。如果一个类型拥有 &lt;code&gt;Copy&lt;&#x2F;code&gt; 特征，一个旧的变量在被赋值给其他变量后仍然可用。&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;任何基本类型的组合可以 &lt;code&gt;Copy&lt;&#x2F;code&gt; ，不需要分配内存或某种形式资源的类型是可以 &lt;code&gt;Copy&lt;&#x2F;code&gt; 的&lt;&#x2F;strong&gt;。如下是一些 &lt;code&gt;Copy&lt;&#x2F;code&gt; 的类型：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;所有整数类型&lt;&#x2F;li&gt;
&lt;li&gt;布尔类型&lt;&#x2F;li&gt;
&lt;li&gt;所有浮点数类型&lt;&#x2F;li&gt;
&lt;li&gt;字符类型&lt;&#x2F;li&gt;
&lt;li&gt;元组，当且仅当其包含的类型也都是 &lt;code&gt;Copy&lt;&#x2F;code&gt; 的时候&lt;&#x2F;li&gt;
&lt;li&gt;不可变引用 &lt;code&gt;&amp;amp;T&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;yin-yong-yu-jie-yin-yong&quot;&gt;引用与解引用&lt;a class=&quot;zola-anchor&quot; href=&quot;#yin-yong-yu-jie-yin-yong&quot; aria-label=&quot;Anchor link for: yin-yong-yu-jie-yin-yong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;常规引用是一个指针类型，指向了对象存储的内存地址。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; x &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; y &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;x&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;assert_eq!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; x&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;assert_eq!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric z-integer z-decimal z-rust&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-arithmetic z-rust&quot;&gt;*&lt;&#x2F;span&gt;y&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;bu-ke-bian-yin-yong&quot;&gt;不可变引用&lt;a class=&quot;zola-anchor&quot; href=&quot;#bu-ke-bian-yin-yong&quot; aria-label=&quot;Anchor link for: bu-ke-bian-yin-yong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; s1 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-rust&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;from&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; len &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-function z-rust&quot;&gt;calculate_length&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;s1&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;The length of &amp;#39;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;&#x2F;span&gt;&amp;#39; is &lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;&#x2F;span&gt;.&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; s1&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; len&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;calculate_length&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;span class=&quot;z-meta z-function z-return-type z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;usize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    s&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;len&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;pic1.zhimg.com&#x2F;80&#x2F;v2-fc68ea4a1fe2e3fe4c5bb523a0a8247c_1440w.jpg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;通过 &lt;code&gt;&amp;amp;s1&lt;&#x2F;code&gt; 语法，我们创建了一个&lt;strong&gt;指向 &lt;code&gt;s1&lt;&#x2F;code&gt; 的引用&lt;&#x2F;strong&gt;，但是并不拥有它。因为并不拥有这个值，当引用离开作用域后，其指向的值也不会被丢弃。&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ke-bian-yin-yong&quot;&gt;可变引用&lt;a class=&quot;zola-anchor&quot; href=&quot;#ke-bian-yin-yong&quot; aria-label=&quot;Anchor link for: ke-bian-yin-yong&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; s &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-rust&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;from&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-support z-function z-rust&quot;&gt;change&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; s&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;change&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-rust&quot;&gt;some_string&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;:&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; String&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    some_string&lt;span class=&quot;z-punctuation z-accessor z-dot z-rust&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function z-rust&quot;&gt;push_str&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;, world&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;s&lt;&#x2F;code&gt; 是可变类型，其次创建一个可变的引用 &lt;code&gt;&amp;amp;mut s&lt;&#x2F;code&gt; 和接受可变引用参数 &lt;code&gt;some_string: &amp;amp;mut String&lt;&#x2F;code&gt; 的函数。&lt;&#x2F;p&gt;
&lt;p&gt;可变引用同时只能存在一个&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;main&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;   &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; &lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; s &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-rust&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;from&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; r1 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;s&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; r2 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;s&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;&#x2F;span&gt; and &lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; r1&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; r2&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 新编译器中，r1,r2作用域在这里结束
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; r3 &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-rust&quot;&gt;mut&lt;&#x2F;span&gt; s&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-support z-macro z-rust&quot;&gt;println!&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-placeholder z-rust&quot;&gt;{}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;,&lt;&#x2F;span&gt; r3&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 老编译器中，r1、r2、r3作用域在这里结束
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;  &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 新编译器中，r3作用域在这里结束
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;引用作用域的结束位置从花括号变成最后一次使用的位置&lt;&#x2F;strong&gt;，因此 &lt;code&gt;r1&lt;&#x2F;code&gt; 借用和 &lt;code&gt;r2&lt;&#x2F;code&gt; 借用在 &lt;code&gt;println!&lt;&#x2F;code&gt; 后，就结束了，此时 &lt;code&gt;r3&lt;&#x2F;code&gt; 可以顺利借用到可变引用。&lt;&#x2F;p&gt;
&lt;h3 id=&quot;xuan-chui-yin-yong-dangling-references&quot;&gt;悬垂引用(Dangling References)&lt;a class=&quot;zola-anchor&quot; href=&quot;#xuan-chui-yin-yong-dangling-references&quot; aria-label=&quot;Anchor link for: xuan-chui-yin-yong-dangling-references&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;指针指向某个值后，这个值被释放掉了，而指针仍然存在，其指向的内存可能不存在任何值或已被其它变量重新使用。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;dangle&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;span class=&quot;z-meta z-function z-return-type z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-keyword z-operator z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;String&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; dangle 返回一个字符串的引用
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; s &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-rust&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;from&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; s 是一个新字符串
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-keyword z-operator z-bitwise z-rust&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;s &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 返回字符串 s 的引用
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 这里 s 离开作用域并被丢弃。其内存被释放。
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;  &lt;span class=&quot;z-comment z-line z-double-slash z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-rust&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; 危险！
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;解决方法是直接返回 &lt;code&gt;String&lt;&#x2F;code&gt;：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; class=&quot;language-rust z-code&quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-storage z-type z-function z-rust&quot;&gt;fn&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function z-rust&quot;&gt;no_dangle&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-parameters z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-parameters z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt; &lt;span class=&quot;z-meta z-function z-return-type z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-separator z-rust&quot;&gt;-&amp;gt;&lt;&#x2F;span&gt; String&lt;&#x2F;span&gt; &lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-begin z-rust&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    &lt;span class=&quot;z-storage z-type z-rust&quot;&gt;let&lt;&#x2F;span&gt; s &lt;span class=&quot;z-keyword z-operator z-assignment z-rust&quot;&gt;=&lt;&#x2F;span&gt; &lt;span class=&quot;z-support z-type z-rust&quot;&gt;String&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-path z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-accessor z-rust&quot;&gt;::&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;from&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-begin z-rust&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-quoted z-double z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;hello&lt;span class=&quot;z-punctuation z-definition z-string z-end z-rust&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-group z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-group z-end z-rust&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-rust&quot;&gt;;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;    s
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-rust&quot;&gt;&lt;span class=&quot;z-meta z-function z-rust&quot;&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-block z-rust&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-block z-end z-rust&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;String&lt;&#x2F;code&gt; 的 &lt;strong&gt;所有权被转移给外面的调用者&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;course.rs&#x2F;basic&#x2F;ownership&#x2F;ownership.html&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;course.rs&#x2F;basic&#x2F;ownership&#x2F;borrowing.html&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Linux | 0644权限</title>
          <pubDate>Tue, 28 Feb 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-02-28-linux-0644/</link>
          <guid>https://inasa.dev/posts/23-02-28-linux-0644/</guid>
          <description xml:base="https://inasa.dev/posts/23-02-28-linux-0644/">&lt;p&gt;模式有 3x3 位标志：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;(owning) User
&lt;ul&gt;
&lt;li&gt;read&lt;&#x2F;li&gt;
&lt;li&gt;write&lt;&#x2F;li&gt;
&lt;li&gt;execute&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Group
&lt;ul&gt;
&lt;li&gt;read&lt;&#x2F;li&gt;
&lt;li&gt;write&lt;&#x2F;li&gt;
&lt;li&gt;execute&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Other
&lt;ul&gt;
&lt;li&gt;read&lt;&#x2F;li&gt;
&lt;li&gt;write&lt;&#x2F;li&gt;
&lt;li&gt;execute&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;每个三元组都很好地编码为八进制数字。&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;rwx oct    meaning
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;--- ---    -------
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;001 01   = execute
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;010 02   = write
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;011 03   = write &amp;amp; execute
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;100 04   = read
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;101 05   = read &amp;amp; execute
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;110 06   = read &amp;amp; write
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;111 07   = read &amp;amp; write &amp;amp; execute
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;所以 0644 是：&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;* (owning) User: read &amp;amp; write
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;* Group: read
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;* Other: read
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;请注意，初始 0 表示八进制表示法，就像 0x 表示十六进制表示法一样。所以每次写纯零时，它实际上是一个八进制零。&lt;&#x2F;p&gt;
&lt;p&gt;这也可以写成：&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-rw-r--r--
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;而完全权限，0777 也可以写成：&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;-rwxrwxrwx
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
</description>
      </item>
      <item>
          <title>Linux | tmpfs &amp; tmpdir</title>
          <pubDate>Sun, 26 Feb 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-02-26-linux-tmpfs/</link>
          <guid>https://inasa.dev/posts/23-02-26-linux-tmpfs/</guid>
          <description xml:base="https://inasa.dev/posts/23-02-26-linux-tmpfs/">&lt;h1 id=&quot;tmpfs&quot;&gt;tmpfs&lt;a class=&quot;zola-anchor&quot; href=&quot;#tmpfs&quot; aria-label=&quot;Anchor link for: tmpfs&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;&lt;strong&gt;T&lt;&#x2F;strong&gt;e&lt;strong&gt;mp&lt;&#x2F;strong&gt;orary &lt;strong&gt;F&lt;&#x2F;strong&gt;ile &lt;strong&gt;S&lt;&#x2F;strong&gt;ystem的简称，数据存储在易失性内存中，而不是一个持久的存储设备。一个类似的结构是RAM磁盘，它显示为一个虚拟磁盘驱动器，并承载一个磁盘文件系统。&lt;&#x2F;p&gt;
&lt;p&gt;存储在tmpfs中的所有内容都是临时性的，即不会在非易失性存储器如硬盘上直接创建文件（尽管根据操作系统的页面替换策略，交换空间被用作备份存储）。重启时，tmpfs中的所有内容都会丢失。&lt;&#x2F;p&gt;
&lt;p&gt;临时文件所使用的内存会随着它所包含的文件而增长和缩小。&lt;&#x2F;p&gt;
&lt;p&gt;许多 Unix 发行版默认为文件系统的 &#x2F;tmp 分支或共享内存启用和使用 tmpfs。可以通过 df 观察到。&lt;&#x2F;p&gt;
&lt;p&gt;而在几乎所有的Linux发行版上，都会在&#x2F;run&#x2F;或&#x2F;var&#x2F;run&#x2F;上挂载一个tmpfs，以存储临时的运行时文件，如PID文件和Unix域套接字。临时的系统文件，如固件变量，存放在&#x2F;sys。&lt;&#x2F;p&gt;
&lt;p&gt;由于RAM的速度比磁盘存储的速度高，tmpfs允许缓存在其中时速度更快，导致整个系统的效率更高，尽管带有页面缓存的操作系统看到的好处较少，因为如果可用内存足够，最近使用的文件页面会保留在内存中。由于RAM在重启时被清除，tmpfs防止系统变得过于杂乱，而不需要用户手动删除临时文件。此外，在RAM中存储文件可以防止磁盘过快填充，并通过减少写入量延长固态硬盘的寿命。&lt;&#x2F;p&gt;
&lt;p&gt;使用RAM来存储文件，而不是物理磁盘，这可以提高性能，减少由于磁盘故障造成的数据丢失风险。与物理磁盘相比，tmpfs的一个优点是速度更快，因为读写是在内存中进行的，而不是在较慢的物理磁盘上。然而，需要注意的是，tmpfs受到系统可用内存数量的限制，文件系统可能需要定期调整大小或清除，以避免内存耗尽。&lt;&#x2F;p&gt;
&lt;pre class=&quot;z-code&quot;&gt;&lt;code&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;┌───────────┬──────────────┬────────────────┐
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│ &#x2F;dev&#x2F;shm  │ always tmpfs │ Linux specific │
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├───────────┼──────────────┼────────────────┤
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│ &#x2F;tmp      │ can be tmpfs │ FHS 1.0        │
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;├───────────┼──────────────┼────────────────┤
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;│ &#x2F;var&#x2F;tmp  │ never tmpfs  │ FHS 1.0        │
&lt;&#x2F;span&gt;&lt;span class=&quot;z-text z-plain&quot;&gt;└───────────┴──────────────┴────────────────┘
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h1 id=&quot;tmp&quot;&gt;&#x2F;tmp&lt;a class=&quot;zola-anchor&quot; href=&quot;#tmp&quot; aria-label=&quot;Anchor link for: tmp&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;&#x2F;tmp是一个目录，被系统和应用程序用来存储只在短时间内需要的临时文件。这些文件通常在系统重新启动时被删除。正因为如此，&#x2F;tmp经常被用来存储运行中的应用程序需要的文件，如日志文件或临时数据。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;var-tmp&quot;&gt;&#x2F;var&#x2F;tmp&lt;a class=&quot;zola-anchor&quot; href=&quot;#var-tmp&quot; aria-label=&quot;Anchor link for: var-tmp&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;&#x2F;var&#x2F;tmp用于长期存储临时文件，这些文件应在重启后持续存在。&lt;&#x2F;p&gt;
&lt;p&gt;一般来说，存储在&#x2F;var&#x2F;tmp中的文件不会被自动删除，而且它们的目的是在重启后仍然存在。然而，在某些情况下，&#x2F;var&#x2F;tmp中的文件可能会被删除，例如，当系统管理员进行系统维护或磁盘空间变满时。&lt;&#x2F;p&gt;
&lt;p&gt;值得注意的是，Linux文件系统层次标准（FHS）建议不要自动删除&#x2F;var&#x2F;tmp中的文件。然而，一些系统管理员可能会选择配置他们的系统来删除&#x2F;var&#x2F;tmp中一定时间内没有被访问或修改的文件。&lt;&#x2F;p&gt;
&lt;h1 id=&quot;dev-shm&quot;&gt;&#x2F;dev&#x2F;shm&lt;a class=&quot;zola-anchor&quot; href=&quot;#dev-shm&quot; aria-label=&quot;Anchor link for: dev-shm&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h1&gt;
&lt;p&gt;&#x2F;dev&#x2F;shm是基于Unix的操作系统中的一个特殊目录，用于创建和访问共享内存段。共享内存是一种技术，它允许多个进程访问一个共同的内存区域，该区域可用于在它们之间共享数据。&lt;&#x2F;p&gt;
&lt;p&gt;在基于Unix的系统中，&#x2F;dev&#x2F;shm是一个虚拟文件系统，它提供了一个使用RAM磁盘的共享内存实现。当一个进程在&#x2F;dev&#x2F;shm中创建一个共享内存段时，操作系统会在RAM盘中创建一个新的文件，该文件有一个代表共享内存段的唯一名称。然后，这个文件可以被其他有必要权限的进程作为共享内存段使用，以访问它。&lt;&#x2F;p&gt;
&lt;p&gt;通过&#x2F;dev&#x2F;shm使用共享内存的好处是，它比其他进程间的通信方法（如管道或套接字）更快，因为数据不在进程间复制。相反，进程可以直接访问同一区域的内存，这可以提高性能并减少开销。&lt;&#x2F;p&gt;
&lt;p&gt;需要注意的是，&#x2F;dev&#x2F;shm中的共享内存段的内容是不稳定的，当系统重启或创建共享内存段的进程明确删除这些内存段时，这些内容就会丢失。因此，确保使用&#x2F;dev&#x2F;shm中的共享内存段的进程正确管理它们的创建和删除，以避免任何数据丢失或系统不稳定是很重要的。&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ol&gt;
&lt;li&gt;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Tmpfs&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;superuser.com&#x2F;questions&#x2F;45342&#x2F;when-should-i-use-dev-shm-and-when-should-i-use-tmp&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Temporary_folder&lt;&#x2F;li&gt;
&lt;li&gt;chatGPT&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</description>
      </item>
      <item>
          <title>MySQL | UUID</title>
          <pubDate>Sun, 26 Feb 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-02-26-mysql-uuid/</link>
          <guid>https://inasa.dev/posts/23-02-26-mysql-uuid/</guid>
          <description xml:base="https://inasa.dev/posts/23-02-26-mysql-uuid/">&lt;p&gt;&lt;code&gt;DEFAULT UUID()&lt;&#x2F;code&gt;是不管用的，需要额外的括号&lt;code&gt;DEFAULT (UUID())&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;但是使用时间戳的时候不需要&lt;code&gt;DEFAULT CURRENT_TIMESTAMP&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;p&gt;相关的函数&lt;code&gt;BIN_TO_UUID()&lt;&#x2F;code&gt;, &lt;code&gt;UUID_TO_BIN()&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;在MySQL 5.7或8.0.12及更早的版本中，不支持使用函数或表达式作为列的默认值。默认值必须是常量，不能是函数或表达式。唯一的例外是，对于&lt;code&gt;TIMESTAMP&lt;&#x2F;code&gt;和&lt;code&gt;DATETIME&lt;&#x2F;code&gt;列，你可以指定&lt;code&gt;CURRENT_TIMESTAMP&lt;&#x2F;code&gt;作为默认值&lt;&#x2F;li&gt;
&lt;li&gt;从MySQL 8.0.13开始，表达式现在可以用作默认值，只要它们被括在括号中。例如，你可以创建一个表，其中一个列的默认值是一个表达式：&lt;code&gt;CREATE TABLE foo (b BINARY(16) DEFAULT (UUID_TO_BIN(UUID ())));&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;UUID()&lt;&#x2F;code&gt;函数返回一个不同的值，每次调用时都会生成一个新的UUID&lt;&#x2F;li&gt;
&lt;li&gt;对于&lt;code&gt;CURRENT_TIMESTAMP&lt;&#x2F;code&gt;，它是一个常量，而不是一个函数。在数据库的上下文中，当我们说&lt;code&gt;CURRENT_TIMESTAMP&lt;&#x2F;code&gt;是一个&quot;常量&quot;，我们是指它是一个固定的标识符，总是返回当前的日期和时间。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;60462208&#x2F;mysql-8-0-13-default-value-as-uuid-not-working&lt;&#x2F;li&gt;
&lt;li&gt;https:&#x2F;&#x2F;blogs.oracle.com&#x2F;mysql&#x2F;post&#x2F;mysql-uuids&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;stackoverflow.com&#x2F;questions&#x2F;46134550&#x2F;mysql-set-default-id-uuid&quot;&gt;MySQL set default id UUID - Stack Overflow&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;dev.mysql.com&#x2F;doc&#x2F;refman&#x2F;8.0&#x2F;en&#x2F;timestamp-initialization.html&quot;&gt;MySQL :: MySQL 8.0 Reference Manual :: 11.2.5 Automatic Initialization and Updating for TIMESTAMP and DATETIME&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Debian | Change kernel</title>
          <pubDate>Sat, 18 Feb 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-02-18-debian-change-kernel/</link>
          <guid>https://inasa.dev/posts/23-02-18-debian-change-kernel/</guid>
          <description xml:base="https://inasa.dev/posts/23-02-18-debian-change-kernel/">&lt;h4 id=&quot;zhao-dao-submenuzhong-de-menuentry-id-option&quot;&gt;找到submenu中的&lt;code&gt;$menuentry_id_option&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhao-dao-submenuzhong-de-menuentry-id-option&quot; aria-label=&quot;Anchor link for: zhao-dao-submenuzhong-de-menuentry-id-option&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;grep&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; submenu &#x2F;boot&#x2F;grub&#x2F;grub.cfg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;返回&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;submenu&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Advanced options for Ubuntu&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;menuentry_id_option&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;gnulinux-advanced-52378de1-0e36-44b8-94d6-33b06437e470&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;gnulinux-advanced-52378de1-0e36-44b8-94d6-33b06437e470&lt;&#x2F;code&gt;就是&lt;code&gt;$menuentry_id_option&lt;&#x2F;code&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;zhao-dao-yao-shi-yong-nei-he-de-cai-dan-xiang&quot;&gt;找到要使用内核的菜单项&lt;a class=&quot;zola-anchor&quot; href=&quot;#zhao-dao-yao-shi-yong-nei-he-de-cai-dan-xiang&quot; aria-label=&quot;Anchor link for: zhao-dao-yao-shi-yong-nei-he-de-cai-dan-xiang&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;grep&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; gnulinux &#x2F;boot&#x2F;grub&#x2F;grub.cfg&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;返回&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;menuentry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Ubuntu&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;class&lt;&#x2F;span&gt; ubuntu&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;class&lt;&#x2F;span&gt; gnu-linux&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;class&lt;&#x2F;span&gt; gnu&lt;span class=&quot;z-variable z-parameter z-option z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-parameter z-shell&quot;&gt; --&lt;&#x2F;span&gt;class&lt;&#x2F;span&gt; os &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;menuentry_id_option&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;gnulinux-simple-52378de1-0e36-44b8-94d6-33b06437e470&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;submenu &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Advanced options for Ubuntu&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;menuentry_id_option&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;gnulinux-advanced-52378de1-0e36-44b8-94d6-33b06437e470&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;	menuentry &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Ubuntu, with Linux 5.15.0-1029-oracle&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --class ubuntu --class gnu-linux --class gnu --class os &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;menuentry_id_option&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;gnulinux-5.15.0-1029-oracle-advanced-52378de1-0e36-44b8-94d6-33b06437e470&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;	menuentry &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;Ubuntu, with Linux 5.15.0-1029-oracle (recovery mode)&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; --class ubuntu --class gnu-linux --class gnu --class os &lt;span class=&quot;z-meta z-group z-expansion z-parameter z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-variable z-shell&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-shell&quot;&gt;menuentry_id_option&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-string z-quoted z-single z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;gnulinux-5.15.0-1029-oracle-recovery-52378de1-0e36-44b8-94d6-33b06437e470&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-section z-expansion z-brace z-begin z-shell&quot;&gt;{&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-arguments z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;&lt;span class=&quot;z-meta z-group z-expansion z-brace z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;xiu-gai-etc-default-grub&quot;&gt;修改&lt;code&gt;&#x2F;etc&#x2F;default&#x2F;grub&lt;&#x2F;code&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#xiu-gai-etc-default-grub&quot; aria-label=&quot;Anchor link for: xiu-gai-etc-default-grub&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;示例&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-begin z-shell&quot;&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;GRUB_DEFAULT=0&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-number-sign z-shell&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite z-assignment z-shell&quot;&gt;GRUB_DEFAULT&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator z-assignment z-shell&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string z-unquoted z-shell&quot;&gt;&lt;span class=&quot;z-string z-quoted z-double z-shell&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-string z-begin z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;gnulinux-advanced-52378de1-0e36-44b8-94d6-33b06437e470&amp;gt;gnulinux-5.15.0-1029-oracle-advanced-52378de1-0e36-44b8-94d6-33b06437e470&lt;span class=&quot;z-punctuation z-definition z-string z-end z-shell&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h4 id=&quot;geng-xin&quot;&gt;更新&lt;a class=&quot;zola-anchor&quot; href=&quot;#geng-xin&quot; aria-label=&quot;Anchor link for: geng-xin&quot; style=&quot;visibility: hidden;&quot;&gt;&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;pre data-lang=&quot;bash&quot; class=&quot;language-bash z-code&quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;update-grub2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-shell z-bash&quot;&gt;&lt;span class=&quot;z-meta z-function-call z-shell&quot;&gt;&lt;span class=&quot;z-variable z-function z-shell&quot;&gt;reboot&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;https:&#x2F;&#x2F;unix.stackexchange.com&#x2F;questions&#x2F;198003&#x2F;set-default-kernel-in-grub&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>Go | Build Constraints 构建约束</title>
          <pubDate>Mon, 02 Jan 2023 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://inasa.dev/posts/23-01-02-go-build-constraints/</link>
          <guid>https://inasa.dev/posts/23-01-02-go-build-constraints/</guid>
          <description xml:base="https://inasa.dev/posts/23-01-02-go-build-constraints/">&lt;p&gt;一个构建约束(构建标签)是文件应包含在包中的条件。构建约束由开始的行注释给出。&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-keyword z-annotation z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-punctuation z-accessor z-colon z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-variable z-function z-go&quot;&gt;build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;约束可以出现在任何类型的源文件中（不仅仅是 Go），但它们必须出现在文件顶部附近，前面只有空行和其他行注释。
这些规则意味着在 Go 文件中，构建约束必须出现在 package 子句之前。&lt;&#x2F;p&gt;
&lt;p&gt;为了区分构建约束和包文档，构建约束后面应该跟一个空行。&lt;&#x2F;p&gt;
&lt;p&gt;构建约束注释被评估为包含由 ||、&amp;amp;&amp;amp; 和 ! 组合的构建标记的表达式,运算符和括号。&lt;&#x2F;p&gt;
&lt;p&gt;例如，当满足&lt;code&gt;linux&lt;&#x2F;code&gt;和&lt;code&gt;386&lt;&#x2F;code&gt;约束时，或者满足&lt;code&gt;darwin&lt;&#x2F;code&gt;而&lt;code&gt;cgo&lt;&#x2F;code&gt;不满足时，以下构建约束约束文件构建：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-keyword z-annotation z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-punctuation z-accessor z-colon z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-variable z-function z-go&quot;&gt;build&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;(linux&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;386)&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;||&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;(darwin&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;!cgo)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;一个文件有多个 &lt;code&gt;&#x2F;&#x2F;go:build&lt;&#x2F;code&gt; 行是错误的。&lt;&#x2F;p&gt;
&lt;p&gt;在特定构建期间，满足以下构建标签：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;目标操作系统，由 &lt;code&gt;runtime.GOOS&lt;&#x2F;code&gt; 拼写，使用 &lt;code&gt;GOOS&lt;&#x2F;code&gt; 环境变量设置。&lt;&#x2F;li&gt;
&lt;li&gt;目标体系结构，由 &lt;code&gt;runtime.GOARCH&lt;&#x2F;code&gt; 拼写，使用 &lt;code&gt;GOARCH&lt;&#x2F;code&gt; 环境变量设置。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;unix&lt;&#x2F;code&gt;，如果 &lt;code&gt;GOOS&lt;&#x2F;code&gt; 是 &lt;code&gt;Unix&lt;&#x2F;code&gt; 或类 &lt;code&gt;Unix&lt;&#x2F;code&gt; 系统。&lt;&#x2F;li&gt;
&lt;li&gt;正在使用的编译器，&lt;code&gt;gc&lt;&#x2F;code&gt;或&lt;code&gt;gccgo&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;cgo&lt;&#x2F;code&gt;，如果支持 &lt;code&gt;cgo&lt;&#x2F;code&gt; 命令（请参阅&lt;code&gt;go help environment&lt;&#x2F;code&gt;中的 &lt;code&gt;CGO_ENABLED&lt;&#x2F;code&gt;）。&lt;&#x2F;li&gt;
&lt;li&gt;每个 Go 主要版本的术语，通过当前版本：从 Go 1.1 版开始的“go1.1”，从 Go 1.12 开始的“go1.12”，等等。&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;-tags&lt;&#x2F;code&gt; 标志给出的任何附加标签（参见&lt;code&gt;go help build&lt;&#x2F;code&gt;）。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;如果文件名在去除扩展名和可能的 &lt;code&gt;_test&lt;&#x2F;code&gt; 后缀后匹配以下任何模式：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;_GOOS&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;_GOARCH&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-keyword z-operator z-go&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-go&quot;&gt;_GOOS_GOARCH&lt;&#x2F;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;（示例：&lt;code&gt;source_windows_amd64.go&lt;&#x2F;code&gt;）其中 &lt;code&gt;GOOS&lt;&#x2F;code&gt; 和 &lt;code&gt;GOARCH&lt;&#x2F;code&gt; 分别代表任何已知的操作系统和体系结构值，然后该文件被认为具有需要这些术语的隐式构建约束（除了文件中的任何显式约束之外）。&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;除了 &lt;code&gt;android&lt;&#x2F;code&gt; 标签和文件之外，使用 &lt;code&gt;GOOS=android&lt;&#x2F;code&gt; 匹配构建标签和文件，就像 &lt;code&gt;GOOS=linux&lt;&#x2F;code&gt; 一样。&lt;&#x2F;li&gt;
&lt;li&gt;除了 &lt;code&gt;illumos&lt;&#x2F;code&gt; 标签和文件之外，使用 &lt;code&gt;GOOS=illumos&lt;&#x2F;code&gt; 匹配构建标签和文件，就像 &lt;code&gt;GOOS=solaris&lt;&#x2F;code&gt; 一样。&lt;&#x2F;li&gt;
&lt;li&gt;除了 &lt;code&gt;ios&lt;&#x2F;code&gt; 标签和文件之外，使用 &lt;code&gt;GOOS=ios&lt;&#x2F;code&gt; 匹配构建标签和文件，就像 &lt;code&gt;GOOS=darwin&lt;&#x2F;code&gt; 一样。&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;要阻止文件被考虑用于构建：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-keyword z-annotation z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-punctuation z-accessor z-colon z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-variable z-function z-go&quot;&gt;build&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;ignore&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;仅在使用 &lt;code&gt;cgo&lt;&#x2F;code&gt; 时构建文件，并且仅在 &lt;code&gt;Linux&lt;&#x2F;code&gt; 和 &lt;code&gt;OS X&lt;&#x2F;code&gt; 上：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-keyword z-annotation z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-punctuation z-accessor z-colon z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-variable z-function z-go&quot;&gt;build&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;cgo&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;(linux&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;||&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;darwin)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;这样的文件通常与另一个实现其他系统默认功能的文件配对，在这种情况下会带有约束：&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-meta z-annotation z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-keyword z-annotation z-go&quot;&gt;go&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-punctuation z-accessor z-colon z-go&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-meta z-variable z-function z-go&quot;&gt;build&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;!(cgo&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;(linux&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;||&lt;&#x2F;span&gt; &lt;span class=&quot;z-meta z-variable z-parameter z-go&quot;&gt;darwin))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;将文件命名为 &lt;code&gt;dns_windows.go&lt;&#x2F;code&gt; 将导致它仅在为 &lt;code&gt;Windows&lt;&#x2F;code&gt; 构建包时被包含；同样，只有在为 32 位 &lt;code&gt;x86&lt;&#x2F;code&gt; 构建包时才会包含 &lt;code&gt;math_386.s&lt;&#x2F;code&gt;。&lt;&#x2F;p&gt;
&lt;p&gt;Go 版本 1.16 及更早版本使用不同的语法来构建约束，带有&lt;code&gt;&#x2F;&#x2F; +build&lt;&#x2F;code&gt;前缀。 gofmt 命令将在遇到旧语法时添加等效的 &lt;code&gt;&#x2F;&#x2F;go:build&lt;&#x2F;code&gt; 约束。&lt;&#x2F;p&gt;
&lt;p&gt;例外，下列使用空格，逗号，多行在新版本中已失效：&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;用空格分隔的构建标记在逻辑上是或&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;  &lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; +build linux darwin
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;用逗号分隔的构建标记在逻辑上是和&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; +build windows,386
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;在多行上构建约束是逻辑和&lt;pre data-lang=&quot;go&quot; class=&quot;language-go z-code&quot;&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; +build windows
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source z-go&quot;&gt;&lt;span class=&quot;z-comment z-line z-go&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-go&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt; +build 386
&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;完整的约束标签可以在&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;golang&#x2F;go&#x2F;blob&#x2F;master&#x2F;src&#x2F;go&#x2F;build&#x2F;syslist.go&quot;&gt;这里&lt;&#x2F;a&gt;找到&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;nofollow noreferrer&quot; href=&quot;https:&#x2F;&#x2F;pkg.go.dev&#x2F;cmd&#x2F;go#hdr-Build_constraints&quot;&gt;Build constraints&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
    </channel>
</rss>
