<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>第 20 章 AI 推理与服务 on Go 语言原本</title>
    <link>/zh-cn/part6hetero/ch20inference/</link>
    <description>Recent content in 第 20 章 AI 推理与服务 on Go 语言原本</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <atom:link href="/zh-cn/part6hetero/ch20inference/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>20.1 推理运行时与 FFI</title>
      <link>/zh-cn/part6hetero/ch20inference/runtime/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/zh-cn/part6hetero/ch20inference/runtime/</guid>
      <description>&lt;h1 id=&#34;201-推理运行时与-ffi&#34;&gt;20.1 推理运行时与 FFI&lt;/h1&gt;&#xA;&lt;p&gt;第 18、19 章反复出现的那道 FFI 边界，到了大模型这里有了它最当下的一副面孔。训练大模型几乎是&#xA;Python 与 CUDA 的天下，可当一个模型训好、要被部署去&lt;strong&gt;服务&lt;/strong&gt;千万次请求时，舞台换了主角，&#xA;Go 在这一层站得很稳。这一章讲 Go 如何承担 AI 的推理与服务，而第一节要先解决最底层的问题:&#xA;Go 自己并不做矩阵乘，它得接入一个本地推理运行时,而这次接入，又是第 18 章那道边界。&lt;/p&gt;&#xA;&lt;h2 id=&#34;2011-训练在-python推理与服务在哪&#34;&gt;20.1.1 训练在 Python，推理与服务在哪&lt;/h2&gt;&#xA;&lt;p&gt;先把分工看清。&lt;strong&gt;训练&lt;/strong&gt;是一件研究性的事:试不同的结构、调超参、看损失曲线，要的是表达的灵活与&#xA;生态的丰富，Python 加 PyTorch、再加 CUDA，是它无可争议的家园。Go 在训练这一侧没有位置，&#xA;也不必有。&lt;/p&gt;&#xA;&lt;p&gt;但&lt;strong&gt;推理与服务&lt;/strong&gt;是另一种事。模型已经冻结，权重不再变，剩下的问题清一色是&lt;strong&gt;系统问题&lt;/strong&gt;:怎么用&#xA;高吞吐、低延迟地服务大量并发请求;怎么把一个几 GB 的模型稳定地装进内存、喂给设备;怎么做成一个&#xA;能一键部署、抗住生产流量、好监控好运维的服务。把这串问题念一遍，会发现它正是 Go 被设计出来要&#xA;解决的那一类:静态编译的单文件部署、天生的并发、可控的内存、成熟的网络栈。所以「训练归 Python、&#xA;推理与服务归 Go」不是偶然的站队，而是两种工作的性质把两门语言各自吸到了它擅长的那一层。&#xA;当下最流行的本地大模型服务 Ollama,正是用 Go 写就的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;2012-接入本地推理运行时又是那道边界&#34;&gt;20.1.2 接入本地推理运行时：又是那道边界&lt;/h2&gt;&#xA;&lt;p&gt;Go 站在服务层，可矩阵乘、注意力、量化这些真正吃算力的活儿，Go 并不亲自做,它把这些交给一个&#xA;&lt;strong&gt;本地推理运行时&lt;/strong&gt;:&lt;code&gt;llama.cpp&lt;/code&gt;/&lt;code&gt;ggml&lt;/code&gt;(C/C++)、ONNX Runtime、或厂商的运行时。这些运行时是&#xA;用 C/C++ 写的高度优化的张量计算库，能调度 CPU 的 SIMD、也能驱动 GPU。Go 要用它们，&#xA;靠的还是 cgo。&lt;/p&gt;&#xA;&lt;p&gt;于是第 18 章的整套机制原样回来了。Ollama 的文档说得很直白:它「包含用 CGO 编译的原生代码」,&#xA;原生推理引擎用 CMake 构建，按需编译出 CUDA、ROCm、Vulkan 等后端。这意味着 15.6 与第 18 章讲过的&#xA;代价一并继承:构建期需要 C/C++ 工具链、失去纯 Go 的轻便（&lt;a href=&#34;../../../part5toolchain/ch15compile/cgo&#34;&gt;15.6.4&lt;/a&gt;),&#xA;运行期每次跨界要付那笔状态转换的税。Ollama 文档甚至点出了一个 15.6 没细说的脆弱处:Go 与 C&#xA;两侧共享的数据结构「可能不同步，导致意外崩溃」,这正是 cgo 把两个世界缝在一起时，缝合处最阴险的&#xA;一类 bug。&lt;/p&gt;</description>
    </item>
    <item>
      <title>20.2 分词与张量</title>
      <link>/zh-cn/part6hetero/ch20inference/tokenize/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/zh-cn/part6hetero/ch20inference/tokenize/</guid>
      <description>&lt;h1 id=&#34;202-分词与张量&#34;&gt;20.2 分词与张量&lt;/h1&gt;&#xA;&lt;p&gt;&lt;a href=&#34;.././runtime&#34;&gt;20.1&lt;/a&gt; 把权重与张量的家安顿在了原生运行时一侧，Go 只在边界上递句柄、搬小数据。&#xA;这一节深入那「小数据」本身:文本怎么变成模型能吃的数字，数字又怎么变回文本。这件看似琐碎的事，&#xA;藏着一个 Go 程序员会心一笑的细节,它几乎就是第 5 章「字符串是一段不可变字节」的直接应用，&#xA;而且一旦疏忽，就会在流式输出时吐出乱码。&lt;/p&gt;&#xA;&lt;h2 id=&#34;2021-分词文本与模型之间的翻译层&#34;&gt;20.2.1 分词：文本与模型之间的翻译层&lt;/h2&gt;&#xA;&lt;p&gt;模型不认识文本。它的输入和输出都是&lt;strong&gt;整数&lt;/strong&gt;,词表里的 token 编号。把人类的文本与模型的整数互相&#xA;翻译的这一层，叫&lt;strong&gt;分词器&lt;/strong&gt;(tokenizer)。它做两件互逆的事:把输入字符串切成一串 token id（编码),&#xA;把模型生成的 token id 拼回字符串（解码)。&lt;/p&gt;&#xA;&lt;p&gt;现代大模型几乎都用&lt;strong&gt;字节对编码&lt;/strong&gt;(Byte-Pair Encoding, BPE)或其变体。它的思路是数据驱动的:&#xA;从最细的单位出发，统计语料里最常一起出现的相邻对，把高频对合并成一个新 token，反复合并，&#xA;最终得到一张几万项的词表，常见词是一个完整 token，生僻词则被拆成几个子词片段。这样既控制了&#xA;词表大小，又能表示任何输入，不会遇到「未登录词」。&lt;/p&gt;&#xA;&lt;h2 id=&#34;2022-为什么是字节而不是字符第-5-章的回响&#34;&gt;20.2.2 为什么是字节，而不是字符：第 5 章的回响&lt;/h2&gt;&#xA;&lt;p&gt;这里有一个对 Go 程序员格外亲切的关键:当代主流的 BPE，是&lt;strong&gt;字节级&lt;/strong&gt;(byte-level)的。它的最小&#xA;单位不是 Unicode 字符（码点)，而是 &lt;strong&gt;UTF-8 字节&lt;/strong&gt;。词表里的合并，发生在字节序列上。&lt;/p&gt;&#xA;&lt;p&gt;这正是第 5 章反复强调的那件事:&lt;a href=&#34;../../../part2lang/ch05data/string&#34;&gt;5.2&lt;/a&gt; 说过，Go 的字符串&#xA;本质是一段&lt;strong&gt;不可变的字节序列&lt;/strong&gt;,&lt;code&gt;range&lt;/code&gt; 一个字符串得到的是码点（rune），而下标索引得到的是字节。&#xA;字节级 BPE 与 Go 的字符串模型严丝合缝:两者都把文本看作字节。于是把一段 Go 字符串喂给字节级&#xA;分词器，概念上不需要任何「字符」的中间层,它处理的就是字符串底层那串字节。&lt;/p&gt;&#xA;&lt;p&gt;但字节级也埋了一个雷，而这个雷恰好踩在 Go 的痛点上:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;一个 token 的边界，未必落在一个完整 UTF-8 字符的边界上。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;一个中文字符在 UTF-8 里占 3 个字节，一个 emoji 可能占 4 个。字节级 BPE 完全可能把这 3 个字节&#xA;&lt;strong&gt;拆进两个相邻的 token&lt;/strong&gt;。这在编码时无所谓，可在&lt;strong&gt;逐 token 解码&lt;/strong&gt;时就出事了:当模型先吐出&#xA;半个字符的那个 token，你拿到的是一串&lt;strong&gt;不完整的 UTF-8 字节&lt;/strong&gt;,它还不构成一个合法的码点，&#xA;要等下一个 token 到达、补齐剩下的字节，才拼得出那个字符。&lt;/p&gt;</description>
    </item>
    <item>
      <title>20.3 服务、批处理与流式</title>
      <link>/zh-cn/part6hetero/ch20inference/serving/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>/zh-cn/part6hetero/ch20inference/serving/</guid>
      <description>&lt;h1 id=&#34;203-服务批处理与流式&#34;&gt;20.3 服务、批处理与流式&lt;/h1&gt;&#xA;&lt;p&gt;前两节把单次推理的底层铺好了:&lt;a href=&#34;.././runtime&#34;&gt;20.1&lt;/a&gt; 经 cgo 接入运行时、安顿好权重与张量,&#xA;&lt;a href=&#34;.././tokenize&#34;&gt;20.2&lt;/a&gt; 讲清了 token 进、token 出。可一个真实的服务，要同时伺候成千上万条这样的&#xA;请求，每条都在持续地吐 token。怎么把它们高效、稳定地组织起来，是一个彻头彻尾的&lt;strong&gt;并发与调度&lt;/strong&gt;&#xA;问题,而这正是 Go 的主场。这一节把第 10 章的通道、第 7 章的 context，落到大模型服务上。&lt;/p&gt;&#xA;&lt;h2 id=&#34;2031-一个请求的一生一条-token-流&#34;&gt;20.3.1 一个请求的一生：一条 token 流&lt;/h2&gt;&#xA;&lt;p&gt;先看清一次生成的形状。大模型是&lt;strong&gt;自回归&lt;/strong&gt;的:它一次只生成一个 token，把这个 token 接回输入，&#xA;再算下一个，循环往复，直到生成结束符或达到长度上限。所以从时间轴上看，&lt;strong&gt;一个请求不是一次&#xA;请求-响应，而是一条随时间流出的 token 流&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;这个形状和 Go 的并发模型天造地设:一个 goroutine 跑生成循环，每算出一个 token 就往一个通道里送,&#xA;下游从通道里收，正是第 10 章「用通信共享内存」的标准句式。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 一个请求 = 一个生成 goroutine，把 token 逐个送进通道&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;generate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;chan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Token&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;defer&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tok&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runtime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;NextToken&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 一次 cgo 调用，算一个 token&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;select&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tok&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                    &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 送给下游（HTTP handler）&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;case&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Done&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 客户端走了，立刻收手&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tok&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;IsEOS&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;这段骨架已经埋下了本节三个主题的种子:&lt;code&gt;out&lt;/code&gt; 通道是&lt;strong&gt;流式&lt;/strong&gt;,&lt;code&gt;ctx.Done()&lt;/code&gt; 是&lt;strong&gt;取消&lt;/strong&gt;,&#xA;而当 &lt;code&gt;out&lt;/code&gt; 满、&lt;code&gt;out &amp;lt;- tok&lt;/code&gt; 阻塞时就是&lt;strong&gt;背压&lt;/strong&gt;。下面逐一展开。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
