<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://debonex.dev/posts</id>
    <title>Debonex site Blog</title>
    <updated>2024-12-10T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://debonex.dev/posts"/>
    <subtitle>Debonex site Blog</subtitle>
    <icon>https://debonex.dev/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[Megatron Pipeline parallel走读]]></title>
        <id>https://debonex.dev/posts/megatron-pipeline-parallel</id>
        <link href="https://debonex.dev/posts/megatron-pipeline-parallel"/>
        <updated>2024-12-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[最近在适配模型训练的工作中，需要修改 Megatron PP切分部分的代码，因此对 Megatron 这部分实现的代码进行了走读，做一下记录。]]></summary>
        <content type="html"><![CDATA[<p>最近在适配模型训练的工作中，需要修改 Megatron PP切分部分的代码，因此对 Megatron 这部分实现的代码进行了走读，做一下记录。</p>
<!-- -->
<p>走读的代码分支为 <code>core_r0.7.0</code>，代码地址 <a href="https://github.com/NVIDIA/Megatron-LM/tree/core_r0.7.0" target="_blank" rel="noopener noreferrer"><code>https://github.com/NVIDIA/Megatron-LM/tree/core_r0.7.0</code></a>，
PP切分的逻辑主要在 <a href="https://github.com/NVIDIA/Megatron-LM/tree/core_r0.7.0/megatron/core/pipeline_parallel" target="_blank" rel="noopener noreferrer"><code>megatron/core/pipeline_parallel</code></a> 目录下。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="pp">PP<a href="https://debonex.dev/posts/megatron-pipeline-parallel#pp" class="hash-link" aria-label="Direct link to PP" title="Direct link to PP">​</a></h2>
<p>直接看核心逻辑，<code>megatron/core/pipeline_parallel/pipeline_parallel.py</code> 中的 <code>forward_backward_pipelining_without_interleaving</code> 函数，
这个函数是 pipeline parallel 的核心逻辑，旨在以流水线方式处理模型的前向和后向传递。</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>后续贴出的代码片段，会省略一些参数检查和断言，以及一些不重要的逻辑。</p></div></div>
<p>总体来看，这个函数包括三个主要流程：</p>
<ul>
<li>warmup</li>
<li>1F1B</li>
<li>cooldown</li>
</ul>
<p>其中，warmup阶段只进行前向，1F1B阶段进行前向和反向传播，cooldown阶段只进行反向。</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="函数定义及其它处理">函数定义及其它处理<a href="https://debonex.dev/posts/megatron-pipeline-parallel#%E5%87%BD%E6%95%B0%E5%AE%9A%E4%B9%89%E5%8F%8A%E5%85%B6%E5%AE%83%E5%A4%84%E7%90%86" class="hash-link" aria-label="Direct link to 函数定义及其它处理" title="Direct link to 函数定义及其它处理">​</a></h3>
<p>关注函数定义中的几个重要的变量。</p>
<ul>
<li><code>data_iterator</code> 参数可以是单个迭代器或迭代器列表，提供要在每个micro batch中处理的数据。</li>
<li><code>model</code> 参数可以是单个 torch.nn.Module 或模块列表，表示当前进程的模型或其片段。</li>
<li><code>num_microbatches</code> 参数指定要将输入数据分成的micro batch数量，而 <code>micro_batch_size</code> 定义了序列长度和每个micro batch的大小。</li>
</ul>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">def</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">forward_backward_pipelining_with_interleaving</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    forward_step_func</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    data_iterator</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Union</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">Iterator</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> List</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">Iterator</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    model</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Union</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">torch</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">nn</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Module</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> List</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">torch</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">nn</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Module</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    num_microbatches</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    seq_length</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    micro_batch_size</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token builtin">int</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>正式进入到函数的逻辑，跳过一些函数的断言和参数检查。首先看到的是关于<code>num_warmup_microbatches</code>的计算，
<code>num_warmup_microbatches</code> 指的是在warmup阶段，每个进程需要计算的batch数，越靠前的PP stage，warmup阶段的batch数越多。</p>
<p>其中，<code>num_microbatches</code> = <code>global_batch_size / micro_batch_size / data_parallel_size</code></p>
<!-- -->
<div class="w-full overflow-auto mb-4"><div class="flex w-fit flex-col gap-px bg-black p-px"><div class="flex gap-px"><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">1</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div></div></div>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Compute number of warmup microbatches.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">num_warmup_microbatches </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    parallel_state</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">get_pipeline_model_parallel_world_size</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> parallel_state</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">get_pipeline_model_parallel_rank</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">num_warmup_microbatches </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token builtin">min</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">num_warmup_microbatches</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> num_microbatches</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">num_microbatches_remaining </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> num_microbatches </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> num_warmup_microbatches</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>随后需要获取两个shape，<code>recv_tensor_shapes</code> 和 <code>send_tensor_shapes</code>，这两个变量的命名和实际用途可能有一些出入，
这两个shape实际分别表示前一个PP stage接受/输出的shape，和当前PP stage接受/输出的shape。</p>
<p>在接受前一个PP stage的前向输出或者向前一个PP stage发送梯度时，需要知道<code>recv_tensor_shapes</code>。
在向后一个PP stage发送前向输出或者接受后一个PP stage的梯度时，则需要知道<code>send_tensor_shapes</code>。</p>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">rank </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> parallel_state</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">get_pipeline_model_parallel_rank</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">recv_tensor_shapes </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> get_tensor_shapes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    rank</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">rank </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    seq_length</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">seq_length</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    micro_batch_size</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">micro_batch_size</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">send_tensor_shapes </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> get_tensor_shapes</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    rank</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">rank</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    seq_length</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">seq_length</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    micro_batch_size</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">micro_batch_size</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="warmup">warmup<a href="https://debonex.dev/posts/megatron-pipeline-parallel#warmup" class="hash-link" aria-label="Direct link to warmup" title="Direct link to warmup">​</a></h3>
<div class="w-full overflow-auto mb-4"><div class="flex w-fit flex-col gap-px bg-black p-px"><div class="flex gap-px"><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">1</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div></div></div>
<p>在warmup阶段，对每个warmup microbatch</p>
<ol>
<li>调用<code>recv_forward</code>接受前一个PP stage的前向输出，（如果是第一个PP stage，<code>forward_step</code>会从dataloader中获取前向需要的数据）</li>
<li>然后执行<code>forward_step</code>，计算前向输出</li>
<li>调用<code>send_forward</code>将前向输出发送给下一个PP stage。</li>
</ol>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Run warmup forward passes.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">num_warmup_microbatches</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    input_tensor </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> recv_forward</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">recv_tensor_shapes</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    output_tensor</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> num_tokens </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> forward_step</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        forward_step_func</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        data_iterator</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        model</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        num_microbatches</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        input_tensor</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        current_microbatch</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">i</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    send_forward</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">output_tensor</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> send_tensor_shapes</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    total_num_tokens </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> num_tokens</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1f1b">1F1B<a href="https://debonex.dev/posts/megatron-pipeline-parallel#1f1b" class="hash-link" aria-label="Direct link to 1F1B" title="Direct link to 1F1B">​</a></h3>
<!-- -->
<div class="w-full overflow-auto mb-4"><div class="flex w-fit flex-col gap-px bg-black p-px"><div class="flex gap-px"><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">4</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">1</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">2</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">3</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600 outline outline-red-500">4</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div></div></div>
<p>在1F1B阶段，如果在warmup阶段没有完成所有的microbatch，需要先接受前一个PP stage的前向输出。
对每一个未完成的microbatch</p>
<ol>
<li>调用<code>forward_step</code>计算前向输出</li>
<li>调用<code>send_forward_recv_backward</code>将前向输出发送给下一个PP stage，并接受后一个PP stage的梯度</li>
<li>如果是最后一个microbatch，需要调用<code>enable_grad_sync</code>，启用梯度同步</li>
<li>调用<code>backward_step</code>计算梯度</li>
<li>如果是最后一个microbatch，调用<code>send_backward</code>将梯度发送给前一个PP stage，否则调用<code>send_backward_recv_forward</code>将梯度发送给前一个PP stage，并接受前一个PP stage的前向输出。</li>
</ol>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Before running 1F1B, need to receive first forward tensor.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># If all microbatches are run in warmup / cooldown phase, then no need to</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># receive this tensor here.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> num_microbatches_remaining </span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    input_tensor </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> recv_forward</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">recv_tensor_shapes</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Run 1F1B in steady state.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">num_microbatches_remaining</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    last_iteration </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">num_microbatches_remaining </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    output_tensor</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> num_tokens </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> forward_step</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        forward_step_func</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        data_iterator</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        model</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        num_microbatches</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        input_tensor</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        current_microbatch</span><span class="token operator" style="color:#393A34">=</span><span class="token plain">i </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> num_warmup_microbatches</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    total_num_tokens </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> num_tokens</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">item</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    output_tensor_grad </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> send_forward_recv_backward</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        output_tensor</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> send_tensor_shapes</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> config</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Enable grad sync for the last microbatch in the batch if the full</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># backward pass completes in the 1F1B stage.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> num_warmup_microbatches </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">and</span><span class="token plain"> last_iteration</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">grad_sync_func </span><span class="token keyword" style="color:#00009f">is</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">or</span><span class="token plain"> rank </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            enable_grad_sync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    input_tensor_grad </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> backward_step</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        input_tensor</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> output_tensor</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> output_tensor_grad</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> model_type</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> config</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> last_iteration</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        input_tensor </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        send_backward</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">input_tensor_grad</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> recv_tensor_shapes</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">else</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        input_tensor </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> send_backward_recv_forward</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            input_tensor_grad</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> recv_tensor_shapes</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> config</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="cooldown">cooldown<a href="https://debonex.dev/posts/megatron-pipeline-parallel#cooldown" class="hash-link" aria-label="Direct link to cooldown" title="Direct link to cooldown">​</a></h3>
<p>在cooldown阶段，恰好与warmup阶段相反，只进行反向传播，对每个warmup microbatch</p>
<ol>
<li>调用<code>recv_backward</code>接受后一个PP stage的梯度</li>
<li>调用<code>backward_step</code>计算梯度</li>
<li>调用<code>send_backward</code>将梯度发送给前一个PP stage</li>
<li>如果是最后一个microbatch，调用<code>enable_grad_sync</code>，启用梯度同步</li>
</ol>
<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Run cooldown backward passes.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> i </span><span class="token keyword" style="color:#00009f">in</span><span class="token plain"> </span><span class="token builtin">range</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">num_warmup_microbatches</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Enable async grad reduction in the last backward pass</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># Note: If grad sync function is provided, only enable</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># async grad reduction in first pipeline stage. Other</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># pipeline stages do grad reduction during pipeline</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic"># bubble.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> i </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> num_warmup_microbatches </span><span class="token operator" style="color:#393A34">-</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">grad_sync_func </span><span class="token keyword" style="color:#00009f">is</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">None</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">or</span><span class="token plain"> rank </span><span class="token operator" style="color:#393A34">==</span><span class="token plain"> </span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            enable_grad_sync</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    output_tensor_grad </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> recv_backward</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">send_tensor_shapes</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    input_tensor_grad </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> backward_step</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        input_tensor</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> output_tensor</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> output_tensor_grad</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> model_type</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> config</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    send_backward</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">input_tensor_grad</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> recv_tensor_shapes</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> config</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<!-- -->
<div class="w-full overflow-auto mb-4"><div class="flex w-fit flex-col gap-px bg-black p-px"><div class="flex gap-px"><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">4</div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600 outline outline-red-500">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">1</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="vpp">VPP<a href="https://debonex.dev/posts/megatron-pipeline-parallel#vpp" class="hash-link" aria-label="Direct link to VPP" title="Direct link to VPP">​</a></h2>
<p>待补充</p>
<!-- -->
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="bubble计算">Bubble计算<a href="https://debonex.dev/posts/megatron-pipeline-parallel#bubble%E8%AE%A1%E7%AE%97" class="hash-link" aria-label="Direct link to Bubble计算" title="Direct link to Bubble计算">​</a></h2>
<div class="mb-4 flex gap-4"><div data-headlessui-state=""><label class="text-sm/6 font-bold" id="headlessui-label-:R1cmglbeh:" for="headlessui-control-:Rmglbeh:" data-headlessui-state="">mode</label><select class="block w-full appearance-none rounded-lg border-none bg-black/5 px-3 py-1.5 text-sm/6 dark:bg-white/5 focus:outline-none data-[focus]:outline-2 data-[focus]:-outline-offset-2 data-[focus]:outline-black/25 dark:data-[focus]:outline-white/25 *:text-black mt-1.5" id="headlessui-control-:Rmglbeh:" data-headlessui-state=""><option value="without_interleaved" selected="">Without Interleaved(PP)</option><option value="interleaved">With Interleaved(VPP)</option><option value="gpipe">GPipe</option></select><span hidden="" style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0;display:none"></span></div><div data-headlessui-state=""><label class="text-sm/6 font-bold" id="headlessui-label-:R1d6glbeh:" for="headlessui-control-:R16glbeh:" data-headlessui-state="">PP</label><input type="number" class="block w-full rounded-lg border-none bg-black/5 px-3 py-1.5 text-sm/6 dark:bg-white/5 focus:outline-none data-[focus]:outline-1 data-[focus]:-outline-offset-2 data-[focus]:outline-black/25 dark:data-[focus]:outline-white/25 mt-1.5" id="headlessui-control-:R16glbeh:" data-headlessui-state="" value="4"><span hidden="" style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0;display:none"></span></div><div data-headlessui-state=""><label class="text-sm/6 font-bold" id="headlessui-label-:R1dmglbeh:" for="headlessui-control-:R1mglbeh:" data-headlessui-state="">Micro Batch</label><input type="number" class="block w-full rounded-lg border-none bg-black/5 px-3 py-1.5 text-sm/6 dark:bg-white/5 focus:outline-none data-[focus]:outline-1 data-[focus]:-outline-offset-2 data-[focus]:outline-black/25 dark:data-[focus]:outline-white/25 mt-1.5" id="headlessui-control-:R1mglbeh:" data-headlessui-state="" value="4"><span hidden="" style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0;display:none"></span></div></div><div class="w-full overflow-auto"><div class="flex w-fit flex-col gap-px bg-black p-px"><div class="flex gap-px"><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div><div class="flex gap-px"><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">1</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">1</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">2</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">2</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">3</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">3</div><div class="flex h-5 w-5 items-center justify-center bg-blue-500 text-xs dark:bg-blue-600">4</div><div class="flex h-5 w-[41px] items-center justify-center border bg-green-500 text-xs dark:bg-green-600">4</div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div><div class="h-5 w-5 bg-slate-400 dark:bg-slate-500"></div></div></div></div><div class="mt-2">Bubble比例: <span class="text-sm">0.75</span></div>]]></content>
        <category label="NLP" term="NLP"/>
        <category label="Megatron" term="Megatron"/>
        <category label="Pipeline parallel" term="Pipeline parallel"/>
        <category label="PyTorch" term="PyTorch"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[如何实现Actix-web中间件]]></title>
        <id>https://debonex.dev/posts/actix-web-middleware</id>
        <link href="https://debonex.dev/posts/actix-web-middleware"/>
        <updated>2023-04-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[最近我在尝试使用 Actix-web 实现一个 Web 服务，其中涉及到了 JWT 鉴权的实现。为此，我想实现一个 middleware 来对请求进行前置处理。]]></summary>
        <content type="html"><![CDATA[<p>最近我在尝试使用 Actix-web 实现一个 Web 服务，其中涉及到了 JWT 鉴权的实现。为此，我想实现一个 <code>middleware</code> 来对请求进行前置处理。
但是，在 Actix-web 中实现一个中间件要比 JavaScript 和 Java 的 Web 框架复杂得多。在这里，我记录一下实现的过程和自己的理解。</p>
<!-- -->
<p>中间件在 Web 服务中起到了非常重要的作用。它可以对请求进行预处理，例如身份验证和缓存，也可以对响应进行后置处理，例如响应压缩。
通过将 Web 服务中的一些通用功能提取成中间件，我们可以提高服务的重用性和可扩展性。这样，开发人员就能更专注于业务逻辑的实现。</p>
<p>一个 <a href="https://nextjs.org/" target="_blank" rel="noopener noreferrer"><code>next.js</code></a> 的中间件通常是一个简单的函数，
它能够获取到 request 的内容并执行异步处理。然后，它可以通过 NextResponse 来重定向请求，或者直接返回一个 Response。下面是一个简单的例子。</p>
<div class="language-ts codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">middleware.ts</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-ts codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> NextResponse </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'next/server'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> NextRequest </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'next/server'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">export</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">middleware</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">request</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> NextRequest</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">  </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> NextResponse</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">redirect</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">new</span><span class="token plain"> </span><span class="token class-name constant" style="color:#36acaa">URL</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'/about-2'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> request</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">url</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>在 Actix-web 中，有三种实现中间件的方式。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="1-appwrap_fn">1. App::wrap_fn<a href="https://debonex.dev/posts/actix-web-middleware#1-appwrap_fn" class="hash-link" aria-label="Direct link to 1. App::wrap_fn" title="Direct link to 1. App::wrap_fn">​</a></h2>
<p>第一种方式与 next.js 的中间件类似，可以使用一个函数来实现中间件。下面是官方文档中的一个示例：</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_Ktv7">main.rs</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token attribute attr-name" style="color:#00a4db">#[actix_web::main]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> app </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">App</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">wrap_fn</span><span class="token punctuation" style="color:#393A34">(</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token closure-params">req</span><span class="token closure-params punctuation" style="color:#393A34">,</span><span class="token closure-params"> srv</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token macro property" style="color:#36acaa">println!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Hi from start. You requested: {}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> req</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">path</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            srv</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">req</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token closure-params">res</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                </span><span class="token macro property" style="color:#36acaa">println!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Hi from response"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">                res</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>这种方式实现中间件比较简单，但是也有一个缺点：</p>
<p><code>warp_fn</code> 是 <code>App</code> 特有的方法，也就是说这种中间件的作用范围是整个 <code>App</code>，无法设定中间件作用于哪些路由。</p>
<p>当然，你也可以在中间件中对路由进行过滤，但是从软件工程的角度来看，这样的设计不符合单一职责原则。路由信息应该在 Application 层控制，
而中间件的主要职责则是处理 HTTP 的请求和响应。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="2-trait-service--trait-transform">2. trait Service &amp; trait Transform<a href="https://debonex.dev/posts/actix-web-middleware#2-trait-service--trait-transform" class="hash-link" aria-label="Direct link to 2. trait Service &amp; trait Transform" title="Direct link to 2. trait Service &amp; trait Transform">​</a></h2>
<p>第二种方式是通过实现 <code>Transform</code> 和 <code>Service</code> 这两个 <code>trait</code> 来实现中间件，<strong>中间件就是一种特殊的 <code>Service</code></strong>, 官方提供的一些中间件也都是通过这种方式实现的。
我也是通过这种方式实现的，因此着重介绍一下这种实现方法。</p>
<p>使用这种方法创建中间件，当新的路由被添加后，也不需要修改中间件的代码；中间件的代码也更具有普适性。如果设计得当，可以将中间件抽离成库，在不同的项目中使用。</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p><code>Transform</code> 和 <code>Service</code> 的定义在不同版本的 Actix-web 中有一些区别，后面的介绍都是基于 Actix-web 4.0 版本。</p></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="service-和-tranform-的关系">Service 和 Tranform 的关系<a href="https://debonex.dev/posts/actix-web-middleware#service-%E5%92%8C-tranform-%E7%9A%84%E5%85%B3%E7%B3%BB" class="hash-link" aria-label="Direct link to Service 和 Tranform 的关系" title="Direct link to Service 和 Tranform 的关系">​</a></h3>
<p><code>Service</code> 定义了一个异步的、将请求转化成响应的操作。在 Actix-web4 中，请求和响应可以是任何类型。在中间件的实现中，
通常使用 <code>ServiceRequest</code> 和 <code>ServiceResponse</code> 作为请求和响应类型。<code>Transform</code> 则定义了服务工厂的接口，该工厂在构建过程中包装内部服务。</p>
<p>因此，在 actix-web 中间件中，<code>Service</code> 扮演的角色类似于上面 <code>next.js</code> 中的 <code>RequestHandler</code>，用于处理请求并返回响应。
而 <code>Transform</code> 则类似于 <code>Service</code> 的工厂，通常将前置 <code>Service</code> 作为参数传递给 <code>Transform</code>。</p>
<p>下面是我理解的 <code>Transform</code> 和 <code>Service</code> 的关系图，<code>Transform</code> 接受 <code>Service</code> 作为参数并生成 <code>middleware</code>，
多个 <code>Transform</code> 链式调用则会生成一个嵌套的 <code>Service</code>。</p>
<div class="text-center"><p><img decoding="async" loading="lazy" src="https://debonex.dev/assets/images/how-middlewares-work-cc9087f6f02db396520fc8f374dad4da.svg" width="596" height="461" class="img_ev3q"></p></div>
<p>每一层的中间件都相当于是一个 <code>Service</code>，在服务端接收到请求后，请求会先被最外层的中间件处理。
每一层的中间件都可以决定是否要调用内层 <code>Service</code> 的 <code>call</code> 方法，或者直接在这一层返回 <code>Response</code>。
中间件也可以在调用 <code>call</code> 方法的前后进行对请求的前置处理和后置处理。</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="trait-transform">trait Transform<a href="https://debonex.dev/posts/actix-web-middleware#trait-transform" class="hash-link" aria-label="Direct link to trait Transform" title="Direct link to trait Transform">​</a></h3>
<p>下面是 <code>trait Transform</code> 的定义，详细介绍请参阅<a href="https://docs.rs/actix-web/4.3.1/actix_web/dev/trait.Transform.html" target="_blank" rel="noopener noreferrer">官方文档</a></p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/// S：前置Service</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/// Req：请求类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/// 下面注释中提到的“生成的Service”就是中间件</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">trait</span><span class="token plain"> </span><span class="token type-definition class-name">Transform</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Req</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// 生成的 Service 的响应类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Response</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// 生成的 Service 的错误类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Error</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// 生成的 Service 的类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Transform</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Service</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Req</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Response</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Response</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Error</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Error</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// 生成 Service 过程的错误类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">InitError</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// Transform 生成 Service 的过程也是异步的，这是包含生成的 Service 的 Future</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Future</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Future</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Output</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Result</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Transform</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">InitError</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// 生成 Service 的方法</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">new_transform</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> service</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Future</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="trait-service">trait Service<a href="https://debonex.dev/posts/actix-web-middleware#trait-service" class="hash-link" aria-label="Direct link to trait Service" title="Direct link to trait Service">​</a></h3>
<p>下面是 <code>trait Service</code> 的定义，详细介绍请参阅<a href="https://docs.rs/actix-web/4.3.1/actix_web/dev/trait.Service.html" target="_blank" rel="noopener noreferrer">官方文档</a></p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">/// Req：请求类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">trait</span><span class="token plain"> </span><span class="token type-definition class-name">Service</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Req</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// Service 的响应类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Response</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// Service 的错误类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Error</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// 包含 Service 响应的 Future</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Future</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Future</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Output</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Result</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Response</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Error</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// 当 `Service` 能够请求处理时返回 `Ready`</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">poll_ready</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ctx</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">task</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">Context</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token lifetime-annotation symbol" style="color:#36acaa">'_</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Poll</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Result</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Error</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">/// 处理请求并异步返回响应</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> req</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Req</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Future</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="实现">实现<a href="https://debonex.dev/posts/actix-web-middleware#%E5%AE%9E%E7%8E%B0" class="hash-link" aria-label="Direct link to 实现" title="Direct link to 实现">​</a></h3>
<p>下面将介绍我如何在 Actix-web 中实现 JWT 鉴权的中间件。
我会尝试解释我自己在实现过程中遇到的一些疑问。
所以重点将放在中间件实现过程中所涉及的类型和生命周期问题上，而不是具体的 JWT 鉴权实现方式。</p>
<p>首先定义中间件以及中间件工厂的 struct，至于为什么在这里要使用 <code>Rc</code> 包装内层 <code>Service</code>，
在后面具体的实现中会讲到。</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token type-definition class-name">AuthMiddlewareFactory</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token type-definition class-name">AuthMiddleware</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">S</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    service</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Rc</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">S</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>接下来是中间件工厂的实现，需要实现 <code>Tranform</code> 这一 trait。</p>
<p>由于创建中间件的过程仅仅是将内层 <code>Service</code> 作为参数传递给中间件，理论上不可能会出错，所以 <code>InitError</code> 是空类型，
<code>Future</code> 也可以直接定义成 <code>Ready</code> 这一具体的类型，表示一个已经就绪的 <code>Future</code>。</p>
<p>注意到中间件 Response 的 body 类型是 <code>EitherBody&lt;B&gt;</code>，
这里的 <a href="https://docs.rs/actix-web/4.3.1/actix_web/body/enum.EitherBody.html" target="_blank" rel="noopener noreferrer"><code>EitherBody</code></a> 是在中间件中常用的类型，
因为中间件的 <code>call</code> 返回的类型可能是内层 <code>Service</code> 返回的类型，也可能返回一个完全不同的类型（通常提前返回错误类型）。
所以需要 <code>EitherBody</code> 来对类型进行统一，<code>EitherBody</code> 接受 1-2 个泛型，第一个泛型表示内层服务返回的类型，第二个泛型（默认是<code>BoxBody</code>）则表示中间件返回的类型。</p>
<p>那为什么要泛型标注成 <code>'static</code> 呢？这个和中间件的实现有关系，下面会解释。</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">/// S: 内层Service类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">/// B: 内层Service的Response的body的类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">impl</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">B</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token class-name">Transform</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">ServiceRequest</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token class-name">AuthMiddlewareFactory</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">where</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// ServiceResponse 接受的第一个泛型表示是 Response body 的类型</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Service</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">ServiceRequest</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Response</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">ServiceResponse</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">B</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Error</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Error</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token lifetime-annotation symbol" style="color:#36acaa">'static</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Future</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token lifetime-annotation symbol" style="color:#36acaa">'static</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">B</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token lifetime-annotation symbol" style="color:#36acaa">'static</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Error</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Error</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">InitError</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Response</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">ServiceResponse</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">EitherBody</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">B</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Future</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Ready</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Result</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Transform</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">InitError</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Transform</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">AuthMiddleware</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">S</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">new_transform</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> service</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Future</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">ready</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Ok</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">AuthMiddleware</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            service</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Rc</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">service</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>最后就是具体中间件的实现了。解释一下可能会有疑惑的几个点。</p>
<ol>
<li>
<p><code>forward_ready!</code>是什么？这是 actix-web 提供的一个宏，用于实现 <code>poll_ready</code>，可以理解为中间件就绪需要内层服务就绪。</p>
</li>
<li>
<p>为什么需要 <code>'static</code> 和 <code>Rc</code>？ 从 19 行开始，我们创建了一个异步闭包，我们把异步闭包的生命周期定义为 <code>'a</code>。
编译器是无法得知 <code>service</code>，以及 <code>service</code> 返回内容的生命周期是否长于 <code>'a</code> 的，所以我们要将它们限定为 <code>'static</code>，
并且创建一个 <code>Rc</code>, 用于在闭包内和闭包外共享 <code>service</code> 的所有权。</p>
</li>
<li>
<p>为什么不使用 <code>Arc</code> 而是用的 <code>Rc</code>， <code>Rc</code> 不是只适用于单线程环境吗？ Actix-web 是用多个单线程的运行时来处理请求的，
一个请求只会在一个线程中处理，所以不会有多线程的问题，这里就使用 <code>Rc</code> 来减少开销。</p>
</li>
</ol>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm"><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">impl</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">B</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token class-name">Service</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">ServiceRequest</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> </span><span class="token class-name">AuthMiddleware</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">S</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">where</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Service</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">ServiceRequest</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Response</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">ServiceResponse</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">B</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Error</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Error</span><span class="token operator" style="color:#393A34">&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token lifetime-annotation symbol" style="color:#36acaa">'static</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token class-name">S</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Future</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token lifetime-annotation symbol" style="color:#36acaa">'static</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token class-name">B</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token lifetime-annotation symbol" style="color:#36acaa">'static</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Error</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Error</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Response</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">ServiceResponse</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">EitherBody</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">B</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">type</span><span class="token plain"> </span><span class="token type-definition class-name">Future</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Pin</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Box</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">dyn</span><span class="token plain"> </span><span class="token class-name">Future</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Output</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Result</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Response</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Error</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token lifetime-annotation symbol" style="color:#36acaa">'static</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 这里实现了 `poll_ready`，调用 self.service.poll_ready</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token macro property" style="color:#36acaa">forward_ready!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">service</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> req</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">ServiceRequest</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">Self</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Future</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> service </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Rc</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">clone</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">self</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">service</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token class-name">Box</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">pin</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">async</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">move</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">// 下面一段都是用于判断请求是否能够通过鉴权，不是关注的重点。</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> auth_pass </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">false</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> token </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> req</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">headers</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"AUTHORIZATION"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">and_then</span><span class="token punctuation" style="color:#393A34">(</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token closure-params">auth_header</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token plain"> auth_header</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">to_str</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">ok</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">filter</span><span class="token punctuation" style="color:#393A34">(</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token closure-params">auth_str</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                    auth_str</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">starts_with</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"bearer "</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">||</span><span class="token plain"> auth_str</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">starts_with</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Bearer "</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token closure-params">auth_str</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">auth_str</span><span class="token punctuation" style="color:#393A34">[</span><span class="token number" style="color:#36acaa">7</span><span class="token punctuation" style="color:#393A34">..</span><span class="token punctuation" style="color:#393A34">]</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">str</span><span class="token punctuation" style="color:#393A34">::</span><span class="token plain">trim</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">unwrap_or</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!</span><span class="token plain">token</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">is_empty</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token class-name">Ok</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">token_data</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">decode_token</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">token</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> redis_client </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> req</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">app_data</span><span class="token punctuation" style="color:#393A34">::</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token namespace" style="opacity:0.7">web</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">Data</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Client</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">ok_or</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">ServerError</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">RedisError</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> current_token </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">get_token</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">redis_client</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> token_data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">claims</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">user_id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">await</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map_err</span><span class="token punctuation" style="color:#393A34">(</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token closure-params">_</span><span class="token closure-params closure-punctuation punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token class-name">ServerError</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">AuthInvalid</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> current_token</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">eq</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">token</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                        </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> extensions </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> req</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">extensions_mut</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                        extensions</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">insert</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">token_data</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">claims</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                        auth_pass </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token boolean" style="color:#36acaa">true</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                    </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!</span><span class="token plain">auth_pass </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                        </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">ServerError</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">AuthExpired</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">into</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">!</span><span class="token plain">auth_pass </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token keyword" style="color:#00009f">return</span><span class="token plain"> </span><span class="token class-name">ServerError</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">AuthInvalid</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">into</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">// 如果鉴权通过，则返回内层Service的结果</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> res </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> service</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">req</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token keyword" style="color:#00009f">await</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token class-name">Ok</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">res</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">map_into_left_body</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="使用">使用<a href="https://debonex.dev/posts/actix-web-middleware#%E4%BD%BF%E7%94%A8" class="hash-link" aria-label="Direct link to 使用" title="Direct link to 使用">​</a></h3>
<p>使用时像下面这样，可以为每一个 route 单独添加中间件，目前 actix-web 支持为一个 <code>ServiceConfig</code> 添加中间件，但是还不支持为一组 route 添加中间件，
所以看起来写法会有点麻烦。</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">config</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">cfg</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> </span><span class="token class-name">ServiceConfig</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    cfg</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">service</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">register</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">service</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">login</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">route</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">""</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">web</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token function" style="color:#d73a49">get</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">to</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">info</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">wrap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">AuthMiddlewareFactory</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">route</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token string" style="color:#e3116c">"/logout"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token namespace" style="opacity:0.7">web</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token function" style="color:#d73a49">post</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">to</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">logout</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">wrap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">AuthMiddlewareFactory</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">route</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token string" style="color:#e3116c">"/add"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            </span><span class="token namespace" style="opacity:0.7">web</span><span class="token namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token function" style="color:#d73a49">post</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">to</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">add_count</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">wrap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">AuthMiddlewareFactory</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>完整的代码实现可以参考下面的</p>
<p><a href="https://github.com/Debonex/actix-jwt-crud" target="_blank" rel="noopener noreferrer">https://github.com/Debonex/actix-jwt-crud</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="3-actix_web_labmiddlewarefrom_fn">3. actix_web_lab::middleware::from_fn<a href="https://debonex.dev/posts/actix-web-middleware#3-actix_web_labmiddlewarefrom_fn" class="hash-link" aria-label="Direct link to 3. actix_web_lab::middleware::from_fn" title="Direct link to 3. actix_web_lab::middleware::from_fn">​</a></h2>
<p>第三种实现方法是用一个额外的库 <a href="https://github.com/robjtede/actix-web-lab" target="_blank" rel="noopener noreferrer"><code>actix-web-lab</code></a> 来实现，这个库是目前 actix-web 的 mantainer 开发的，
这个库包含了很多实验性的功能，未来可能会添加到 actix-web 中。</p>
<p>使用这个 <a href="https://docs.rs/actix-web-lab/latest/actix_web_lab/middleware/fn.from_fn.html" target="_blank" rel="noopener noreferrer"><code>from_fn</code></a>，可以简化上面中间件的实现。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="references">References<a href="https://debonex.dev/posts/actix-web-middleware#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References">​</a></h2>
<ol>
<li><a href="https://actix.rs/docs/" target="_blank" rel="noopener noreferrer">https://actix.rs/docs/</a></li>
<li><a href="https://imfeld.dev/writing/actix-web-middleware" target="_blank" rel="noopener noreferrer">https://imfeld.dev/writing/actix-web-middleware</a></li>
</ol>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="其它">其它<a href="https://debonex.dev/posts/actix-web-middleware#%E5%85%B6%E5%AE%83" class="hash-link" aria-label="Direct link to 其它" title="Direct link to 其它">​</a></h2>
<p>这篇 blog 的跨度时间很长，所以内容逻辑可能有点乱，从 4 月份就开始开的坑，原本是想给旧的博客添上一些内容，但是本人有点拖延，而且 5 月份还换了工作，所以内容一直搁置了，
新的工作空闲时间比较少，一直也没有时间写。但是我一直觉得自己的总结输出能力需要提高，所以还是想把这篇总结写完，算是一个提高总结能力的练习吧。
以后也会把一些学到的东西总结下来，不过可能篇幅会短一些，尽量把东西讲清楚。</p>
<p>今天是 7 月 8 号，花了一个下午的时间把这篇总结补全了，也算是给自己一个交代吧。顺便也用 docusaurus 重新部署了博客，之前的博客是自己用 next.js 写的，
大量时间都花在了博客框架的实现上了，最后博文没写几篇。之前实现了从 Notion 爬取内容，然后生成静态博客，这部分可能不太好迁移，可能以后会放个外链。</p>
<p>写博客最重要的是内容，所以还是少折腾框架，多写内容吧 😓。</p>]]></content>
        <category label="Rust" term="Rust"/>
        <category label="Actix-web" term="Actix-web"/>
        <category label="JWT" term="JWT"/>
        <category label="Middleware" term="Middleware"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Rust单向链表中的所有权]]></title>
        <id>https://debonex.dev/posts/rust-single-linked-list-ownership2</id>
        <link href="https://debonex.dev/posts/rust-single-linked-list-ownership2"/>
        <updated>2022-08-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[前段时间在尝试用 Rust 刷 Leetcode，一开始感觉没什么问题。直到遇到单向链表，我开始和编译器作斗争了。]]></summary>
        <content type="html"><![CDATA[<p>前段时间在尝试用 Rust 刷 Leetcode，一开始感觉没什么问题。直到遇到单向链表，我开始和编译器作斗争了。</p>
<!-- -->
<p>一开始是根据编译器的提示稀里糊涂地解决的，加一个 <code>as_ref()</code>，加一个 <code>clone()</code> 什么的。
问题虽然是解决了，但是代码非常不优雅，也有很多冗余，自己也糊里糊涂的。今天尝试一下把思路理清楚。</p>
<p>用一个简单的题来做说明。 <a href="https://leetcode.cn/problems/merge-two-sorted-lists/" target="_blank" rel="noopener noreferrer">Leetcode.21 合并两个有序链表</a></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="ownership--borrowing">Ownership &amp; Borrowing<a href="https://debonex.dev/posts/rust-single-linked-list-ownership2#ownership--borrowing" class="hash-link" aria-label="Direct link to Ownership &amp; Borrowing" title="Direct link to Ownership &amp; Borrowing">​</a></h2>
<p>先简单回顾一下 Rust 中 ownership 和 borrow 的基本规则</p>
<ul>
<li>Each value in Rust has an owner.</li>
<li>There can only be one owner at a time.</li>
<li>When the owner goes out of scope, the value will be dropped.</li>
<li>At any given time, you can have either one mutable reference or any number of immutable references.</li>
<li>References must always be valid.</li>
</ul>
<p>按我的理解就是，Rust 中的一个值只能被一个变量所有，如果有另一个变量想要使用这个值，必须要用 <code>&amp;</code> 借用，但是最多同时只能有一个 <code>&amp;mut</code> 借用。</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="enum-option-相关">Enum Option 相关<a href="https://debonex.dev/posts/rust-single-linked-list-ownership2#enum-option-%E7%9B%B8%E5%85%B3" class="hash-link" aria-label="Direct link to Enum Option 相关" title="Direct link to Enum Option 相关">​</a></h2>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token attribute attr-name" style="color:#00a4db">#[derive(PartialEq, Eq, Clone, Debug)]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">struct</span><span class="token plain"> </span><span class="token type-definition class-name">ListNode</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> val</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">i32</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> next</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Option</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Box</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">ListNode</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>上面是题目给定的单向链表结构，用 <code>Option&lt;Box&lt;ListNode&gt;&gt;</code> 来表示链表的节点。
这里主要看一下 <code>Option</code> 一些方法对所有权的影响。</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="fn-unwrapself---t"><code>fn unwrap(self) -&gt; T</code><a href="https://debonex.dev/posts/rust-single-linked-list-ownership2#fn-unwrapself---t" class="hash-link" aria-label="Direct link to fn-unwrapself---t" title="Direct link to fn-unwrapself---t">​</a></h3>
<p><code>unwrap</code> 是 <code>Option</code> 中最常用的方法，它可以把一个 <code>Some</code> 的值取出来，如果是 <code>None</code>，就会 <code>panic</code>。
这里值得注意的是 <code>unwrap</code> 会消费变量的所有权，比如下面的代码是无法通过编译的。</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> some_string </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Some</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"szzy"</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">to_string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 这里 some_string 的所有权被消费,"szzy" 这个值的所有权转移给了 unwrapped_string。</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> unwrapped_string </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> some_string</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">unwrap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 这里编译不通过，因为 some_string 这时候已经变成一个无效的变量，它不拥有任何值。</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property" style="color:#36acaa">println!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"{:?}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> unwrapped_string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="fn-as_refself---optiont"><code>fn as_ref(&amp;self) -&gt; Option&lt;&amp;T&gt;</code><a href="https://debonex.dev/posts/rust-single-linked-list-ownership2#fn-as_refself---optiont" class="hash-link" aria-label="Direct link to fn-as_refself---optiont" title="Direct link to fn-as_refself---optiont">​</a></h3>
<p><code>as_ref</code> 的作用是把一个 <code>&amp;Option&lt;T&gt;</code> 转化成 <code>Option&lt;&amp;T&gt;</code>。
类似的，<code>as_mut</code> 可以把一个 <code>&amp;mut Option&lt;T&gt;</code> 转化成 <code>Option&lt;&amp;mut T&gt;</code>。</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="fn-takemut-self---optiont"><code>fn take(&amp;mut self) -&gt; Option&lt;T&gt;</code><a href="https://debonex.dev/posts/rust-single-linked-list-ownership2#fn-takemut-self---optiont" class="hash-link" aria-label="Direct link to fn-takemut-self---optiont" title="Direct link to fn-takemut-self---optiont">​</a></h3>
<p><code>take</code> 会将 <code>Option</code> 的值取走，并用 <code>None</code> 代替。不过虽然这个方法会转移值的所有权，但是原来的变量还是有效的，只不过变成 <code>None</code> 了。
因此下面的代码是可以通过编译的。</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> some_string </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Some</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"szzy"</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">to_string</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 这里 "szzy" 这个值的所有权转移给了 _take 变量。</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> _take </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> some_string</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">take</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// 这里 some_string 仍然是有效的变量，只不过它拥有的值是 `None`。</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property" style="color:#36acaa">println!</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"{:?}"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> some_string</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="题解">题解<a href="https://debonex.dev/posts/rust-single-linked-list-ownership2#%E9%A2%98%E8%A7%A3" class="hash-link" aria-label="Direct link to 题解" title="Direct link to 题解">​</a></h2>
<p>把上面的东西弄懂之后，处理单向链表就比较简单了。</p>
<!-- -->
<!-- -->
<div class="grid grid-cols-1 rounded-md bg-[#f6f8fa] md:grid-cols-[auto,minmax(0,1fr)] dark:bg-dark-deep"><div class="md:col-span-2 p-1 px-2 bg-[var(--ifm-background-surface-color)] relative"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="inline h-5 w-5 fill-current align-middle cursor-pointer hover:opacity-60 transition-opacity"><path d="M40 48c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h48c13.3 0 24-10.7 24-24V72c0-13.3-10.7-24-24-24zm152 16c-17.7 0-32 14.3-32 32s14.3 32 32 32h288c17.7 0 32-14.3 32-32s-14.3-32-32-32zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32h288c17.7 0 32-14.3 32-32s-14.3-32-32-32zm0 160c-17.7 0-32 14.3-32 32s14.3 32 32 32h288c17.7 0 32-14.3 32-32s-14.3-32-32-32zM16 232v48c0 13.3 10.7 24 24 24h48c13.3 0 24-10.7 24-24v-48c0-13.3-10.7-24-24-24H40c-13.3 0-24 10.7-24 24m24 136c-13.3 0-24 10.7-24 24v48c0 13.3 10.7 24 24 24h48c13.3 0 24-10.7 24-24v-48c0-13.3-10.7-24-24-24z"></path></svg><span class="absolute left-1/2 transform -translate-x-1/2">Solution</span></div><div class="py-2"><div style="padding-left:0.5rem" class="cursor-pointer select-none border py-0.5 pr-4 font-mono text-sm transition-colors duration-75 hover:bg-light-dim dark:hover:bg-[#282e34] border-transparent"><svg viewBox="0 0 1024 1024" class="inline h-3.5 w-3.5 fill-current align-middle transition-transform rotate-90"><path d="M837.845 701.312a64 64 0 0 1-90.496 0L505.984 459.947 264.619 701.312a64 64 0 1 1-90.496-90.496l286.592-286.635a64 64 0 0 1 90.496 0l286.634 286.635a64 64 0 0 1 0 90.453z"></path></svg><span class="pl-1 align-middle">data_structure</span></div><div class="origin-top transition-all max-h-0 scale-y-0"><div style="padding-left:1.25rem" class="cursor-pointer select-none border py-0.5 pr-4 font-mono text-sm transition-colors duration-75 hover:bg-light-dim dark:hover:bg-[#282e34] border-transparent"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" class="inline h-3.5 w-3.5 fill-current align-middle"><path d="M0 64C0 28.65 28.65 0 64 0h165.5c17 0 33.2 6.743 45.2 18.75l90.6 90.55c12 12 18.7 28.2 18.7 45.2V448c0 35.3-28.7 64-64 64H64c-35.35 0-64-28.7-64-64zm336 384V160h-80c-17.7 0-32-14.3-32-32V48H64c-8.84 0-16 7.16-16 16v384c0 8.8 7.16 16 16 16h256c8.8 0 16-7.2 16-16"></path></svg><span class="pl-1 align-middle">mod.rs</span></div><div style="padding-left:1.25rem" class="cursor-pointer select-none border py-0.5 pr-4 font-mono text-sm transition-colors duration-75 hover:bg-light-dim dark:hover:bg-[#282e34] border-transparent"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" class="inline h-3.5 w-3.5 fill-current align-middle"><path d="M0 64C0 28.65 28.65 0 64 0h165.5c17 0 33.2 6.743 45.2 18.75l90.6 90.55c12 12 18.7 28.2 18.7 45.2V448c0 35.3-28.7 64-64 64H64c-35.35 0-64-28.7-64-64zm336 384V160h-80c-17.7 0-32-14.3-32-32V48H64c-8.84 0-16 7.16-16 16v384c0 8.8 7.16 16 16 16h256c8.8 0 16-7.2 16-16"></path></svg><span class="pl-1 align-middle">linked_list.rs</span></div></div><div style="padding-left:0.5rem" class="cursor-pointer select-none border py-0.5 pr-4 font-mono text-sm transition-colors duration-75 hover:bg-light-dim dark:hover:bg-[#282e34] border-transparent"><svg viewBox="0 0 1024 1024" class="inline h-3.5 w-3.5 fill-current align-middle transition-transform rotate-180"><path d="M837.845 701.312a64 64 0 0 1-90.496 0L505.984 459.947 264.619 701.312a64 64 0 1 1-90.496-90.496l286.592-286.635a64 64 0 0 1 90.496 0l286.634 286.635a64 64 0 0 1 0 90.453z"></path></svg><span class="pl-1 align-middle">solutions</span></div><div class="origin-top transition-all max-h-[100vh]"><div style="padding-left:1.25rem" class="cursor-pointer select-none border py-0.5 pr-4 font-mono text-sm transition-colors duration-75 hover:bg-light-dim dark:hover:bg-[#282e34] border-transparent"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" class="inline h-3.5 w-3.5 fill-current align-middle"><path d="M0 64C0 28.65 28.65 0 64 0h165.5c17 0 33.2 6.743 45.2 18.75l90.6 90.55c12 12 18.7 28.2 18.7 45.2V448c0 35.3-28.7 64-64 64H64c-35.35 0-64-28.7-64-64zm336 384V160h-80c-17.7 0-32-14.3-32-32V48H64c-8.84 0-16 7.16-16 16v384c0 8.8 7.16 16 16 16h256c8.8 0 16-7.2 16-16"></path></svg><span class="pl-1 align-middle">mod.rs</span></div><div style="padding-left:1.25rem" class="cursor-pointer select-none border py-0.5 pr-4 font-mono text-sm transition-colors duration-75 hover:bg-light-dim dark:hover:bg-[#282e34] border-primary-main bg-light-dim text-primary-main dark:!bg-[#39414a]"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" class="inline h-3.5 w-3.5 fill-current align-middle"><path d="M0 64C0 28.65 28.65 0 64 0h165.5c17 0 33.2 6.743 45.2 18.75l90.6 90.55c12 12 18.7 28.2 18.7 45.2V448c0 35.3-28.7 64-64 64H64c-35.35 0-64-28.7-64-64zm336 384V160h-80c-17.7 0-32-14.3-32-32V48H64c-8.84 0-16 7.16-16 16v384c0 8.8 7.16 16 16 16h256c8.8 0 16-7.2 16-16"></path></svg><span class="pl-1 align-middle">solution_0021.rs</span></div></div><div style="padding-left:0.5rem" class="cursor-pointer select-none border py-0.5 pr-4 font-mono text-sm transition-colors duration-75 hover:bg-light-dim dark:hover:bg-[#282e34] border-transparent"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512" class="inline h-3.5 w-3.5 fill-current align-middle"><path d="M0 64C0 28.65 28.65 0 64 0h165.5c17 0 33.2 6.743 45.2 18.75l90.6 90.55c12 12 18.7 28.2 18.7 45.2V448c0 35.3-28.7 64-64 64H64c-35.35 0-64-28.7-64-64zm336 384V160h-80c-17.7 0-32-14.3-32-32V48H64c-8.84 0-16 7.16-16 16v384c0 8.8 7.16 16 16 16h256c8.8 0 16-7.2 16-16"></path></svg><span class="pl-1 align-middle">lib.rs</span></div></div><div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv codeBlockLinesWithNumbering_o6Pm"><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token keyword" style="color:#00009f">use</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">super</span><span class="token punctuation" style="color:#393A34">::</span><span class="token class-name">Solution</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">use</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">crate</span><span class="token module-declaration namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token module-declaration namespace" style="opacity:0.7">data_structure</span><span class="token module-declaration namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token module-declaration namespace" style="opacity:0.7">linked_list</span><span class="token module-declaration namespace punctuation" style="opacity:0.7;color:#393A34">::</span><span class="token class-name">ListNode</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token keyword" style="color:#00009f">impl</span><span class="token plain"> </span><span class="token class-name">Solution</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">pub</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">fn</span><span class="token plain"> </span><span class="token function-definition function" style="color:#d73a49">merge_two_lists</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> list1</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Option</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Box</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">ListNode</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> list2</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">Option</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Box</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">ListNode</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">-&gt;</span><span class="token plain"> </span><span class="token class-name">Option</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">Box</span><span class="token operator" style="color:#393A34">&lt;</span><span class="token class-name">ListNode</span><span class="token operator" style="color:#393A34">&gt;&gt;</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> dummy </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">ListNode</span><span class="token punctuation" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">new</span><span class="token punctuation" style="color:#393A34">(</span><span class="token operator" style="color:#393A34">-</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> tail </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token keyword" style="color:#00009f">mut</span><span class="token plain"> dummy</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> list1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">is_some</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;&amp;</span><span class="token plain"> list2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">is_some</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">// 这里注意到 unwrap 会消费所有权</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">// 所以要先调用 as_ref 方法创建一个引用</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">// 再调用 unwrap 消费的就是对引用的所有权</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token comment" style="color:#999988;font-style:italic">// 否则下面的 list1 和 list2 就变成无效变量了</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> val1 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> list1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">as_ref</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">unwrap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">let</span><span class="token plain"> val2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> list2</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">as_ref</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">unwrap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">val</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> val1 </span><span class="token operator" style="color:#393A34">&lt;</span><span class="token plain"> val2 </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// 第一个节点的所有权转移给了 tail.next</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                tail</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> list1</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// 这里把 tail 指向它的下一个节点</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// 只需要注意一下 tail 的类型是 &amp;mut ListNode</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                tail </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> tail</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">as_mut</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">unwrap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// 这里需要用 take 将第二个节点的所有权给到 list1</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                </span><span class="token comment" style="color:#999988;font-style:italic">// 否则在下一个循环里 list1 就变成无效变量了</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                list1 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> tail</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">take</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                tail</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> list2</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                tail </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> tail</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">as_mut</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">unwrap</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">                list2 </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> tail</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">take</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">            </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain" style="display:inline-block"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        tail</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> list1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">is_none</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> list2 </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> list1 </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">        dummy</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">next</span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span></span><br></span><span class="token-line codeLine_lJS_" style="color:#393A34"><span class="codeLineNumber_Tfdd"></span><span class="codeLineContent_feaV"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span></span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="总结">总结<a href="https://debonex.dev/posts/rust-single-linked-list-ownership2#%E6%80%BB%E7%BB%93" class="hash-link" aria-label="Direct link to 总结" title="Direct link to 总结">​</a></h2>
<p>本人目前对 Rust 的认识比较浅，可能有很多说错的地方，以后理解深刻之后再回来修改。</p>
<p>这里用到的单向链表是简化之后的版本，实际生产环境中用到的 Rust 单向链表和双向链表实现要复杂的多，要用到大量的 unsafe 代码。
水平有限，这里就不展开了，具体可以参考这个仓库的实现：<a href="https://github.com/Amanieu/intrusive-rs" target="_blank" rel="noopener noreferrer">Amanieu/intrusive-rs</a></p>]]></content>
        <category label="Rust" term="Rust"/>
        <category label="ownership" term="ownership"/>
    </entry>
</feed>