<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tony Bai &#187; Python</title>
	<atom:link href="http://tonybai.com/tag/python/feed/" rel="self" type="application/rss+xml" />
	<link>https://tonybai.com</link>
	<description>一个程序员的心路历程</description>
	<lastBuildDate>Sun, 12 Apr 2026 22:30:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>从 1960 到 2026：一文看透 Java、Go、Python 垃圾回收器的原理与演进</title>
		<link>https://tonybai.com/2026/04/07/garbage-collectors-deep-dive/</link>
		<comments>https://tonybai.com/2026/04/07/garbage-collectors-deep-dive/#comments</comments>
		<pubDate>Tue, 07 Apr 2026 00:17:15 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[ColoredPointers]]></category>
		<category><![CDATA[ConcurrentMarking]]></category>
		<category><![CDATA[CopyingCollector]]></category>
		<category><![CDATA[CPython]]></category>
		<category><![CDATA[Cycles]]></category>
		<category><![CDATA[EscapeAnalysis]]></category>
		<category><![CDATA[G1GC]]></category>
		<category><![CDATA[GarbageCollection]]></category>
		<category><![CDATA[GC]]></category>
		<category><![CDATA[GenerationalHypothesis]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[HybridWriteBarrier]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JVM]]></category>
		<category><![CDATA[latency]]></category>
		<category><![CDATA[MarkAndSweep]]></category>
		<category><![CDATA[MemoryManagement]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[ReferenceCounting]]></category>
		<category><![CDATA[StopTheWorld]]></category>
		<category><![CDATA[STW]]></category>
		<category><![CDATA[Throughput]]></category>
		<category><![CDATA[TriColorMarking]]></category>
		<category><![CDATA[WriteBarrier]]></category>
		<category><![CDATA[ZGC]]></category>
		<category><![CDATA[三色标记]]></category>
		<category><![CDATA[全线停顿]]></category>
		<category><![CDATA[内存管理]]></category>
		<category><![CDATA[写屏障]]></category>
		<category><![CDATA[分代假说]]></category>
		<category><![CDATA[吞吐量]]></category>
		<category><![CDATA[垃圾回收]]></category>
		<category><![CDATA[复制算法]]></category>
		<category><![CDATA[并发标记]]></category>
		<category><![CDATA[延迟]]></category>
		<category><![CDATA[引用计数]]></category>
		<category><![CDATA[循环引用]]></category>
		<category><![CDATA[有色指针]]></category>
		<category><![CDATA[标记清除]]></category>
		<category><![CDATA[混合写屏障]]></category>
		<category><![CDATA[逃逸分析]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6154</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/04/07/garbage-collectors-deep-dive 大家好，我是Tony Bai。 为什么 Java 的 G1GC 需要设置停顿目标？Go 的混合写屏障是如何消除栈重扫的？Python 又是如何解决引用计数无法处理的循环引用？ 垃圾回收（GC）不仅是语言运行时的核心，更是理解高性能系统绕不开的坎。 本文翻译自Shubham Raizada的文章《Garbage Collection: From First Principles to Modern Collectors in Java, Go and Python》。 此文通过对历史经典论文的溯源和对现代主流语言底层实现的拆解，构建了一套完整的 GC 知识体系。 文章涵盖了从基础的标记-清除、复制与整理算法，到复杂的三色标记抽象、写屏障机制以及有色指针技术。 无论你是想调优 JVM 性能，还是试图理解 Go 并发垃圾收集的吞吐成本，这篇文章都将为你提供从理论支撑到代码实现的全景视角。 以下是译文全文： 在过去的几年里，我的技术栈经历了从 Java 到 Go，再到 Rust，现在又回到了 Java 的过程。 在这些语言之间切换时，一直绕不开的一个话题就是垃圾回收（Garbage Collection, GC）。Java 和 Go 有 GC，而 Rust 没有。 在基准测试、延迟讨论以及“为什么这个服务变慢了”的对话中，GC 总会出现在某个角落。我经常听到关于 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/04/07/garbage-collectors-deep-dive">本文永久链接</a> &#8211; https://tonybai.com/2026/04/07/garbage-collectors-deep-dive</p>
<p>大家好，我是Tony Bai。</p>
<p>为什么 Java 的 G1GC 需要设置停顿目标？Go 的混合写屏障是如何消除栈重扫的？Python 又是如何解决引用计数无法处理的循环引用？</p>
<p>垃圾回收（GC）不仅是语言运行时的核心，更是理解高性能系统绕不开的坎。</p>
<p>本文翻译自Shubham Raizada的文章《<a href="https://shbhmrzd.github.io/systems/garbage-collection/memory-management/2026/04/01/garbage-collectors-deep-dive.html">Garbage Collection: From First Principles to Modern Collectors in Java, Go and Python</a>》。</p>
<p>此文通过对历史经典论文的溯源和对现代主流语言底层实现的拆解，构建了一套完整的 GC 知识体系。</p>
<p>文章涵盖了从基础的标记-清除、复制与整理算法，到复杂的三色标记抽象、写屏障机制以及有色指针技术。</p>
<p>无论你是想调优 JVM 性能，还是试图理解 Go 并发垃圾收集的吞吐成本，这篇文章都将为你提供从理论支撑到代码实现的全景视角。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/agentic-api-in-action-qr.png" alt="" /></p>
<p>以下是译文全文：</p>
<hr />
<p>在过去的几年里，我的技术栈经历了从 Java 到 Go，再到 Rust，现在又回到了 Java 的过程。</p>
<p>在这些语言之间切换时，一直绕不开的一个话题就是垃圾回收（Garbage Collection, GC）。Java 和 Go 有 GC，而 Rust 没有。</p>
<p>在基准测试、延迟讨论以及“为什么这个服务变慢了”的对话中，GC 总会出现在某个角落。我经常听到关于 GC pauses（GC 停顿）、throughput overhead（吞吐量开销）和 write barriers（写屏障）的讨论，但我并不完全理解底层发生了什么。</p>
<p>在追溯起源时，我读到了 McCarthy 1960 年的论文，这篇论文因引入 Lisp 而闻名，但它也是首次描述 mark-and-sweep（标记-清除）的地方。</p>
<p>这又引导我阅读了 Wilson 1992 年的综述《Uniprocessor Garbage Collection Techniques》，该文将随后的所有发展组织成了一个清晰的分类学。</p>
<p>阅读这两篇文献让我更容易理解现代垃圾收集器，因为 G1GC、ZGC、Go 的并发收集器以及 CPython 的混合方案全都是这些论文所描述思想的变体。我还用 Go 编写了一个简单的玩具级 GC，以便亲自观察其机制。</p>
<p>以下是我在这一过程中的笔记。</p>
<h2>起源论文</h2>
<h3>McCarthy (1960): <a href="https://dl.acm.org/doi/10.1145/367177.367199">Recursive Functions of Symbolic Expressions and Their Computation by Machine</a></h3>
<p>这篇论文因引入 Lisp 而闻名，但垃圾回收器几乎是作为实现细节被埋藏在其中的。McCarthy 需要一种方法来管理符号表达式的内存。Lisp 程序操作的是嵌套的列表（lists of lists of lists），这种递归结构使得要求程序员手动释放内存变得不切实际。因此，他描述了一种自动执行此操作的机制。</p>
<p>该机制分为两个阶段。首先，从程序正在活跃使用的 root（根）变量开始，遍历它们引用的每一个对象，将每个对象标记为 reachable（可达）。其次，扫描所有内存。任何未被标记的对象都是垃圾。将它们重新添加回 free list（空闲列表）。</p>
<p>这就是 mark-and-sweep（标记-清除）。它能自然地处理 cycles（循环引用，因为不可达的循环永远不会被标记），不需要逐个对象的簿记工作，并让程序员可以完全忽略内存管理。</p>
<p>其代价是程序在收集器运行时必须完全停止。每一次分配、每一次计算，所有一切都会冻结，直到标记和清除完成。对于 McCarthy 在 1960 年编写的程序来说，这完全是合理的。</p>
<p>随着程序规模变大并进入对延迟敏感的环境（如处理每秒数千次请求的 Web 服务器），stop-the-world（全线停顿）成了一个难以接受的权衡。现代 GC 研究产生的大部分成果都是为了回答一个问题：如何在不停止世界的情况下进行垃圾内存回收？</p>
<h3>Wilson (1992): <a href="https://dl.acm.org/doi/10.5555/645648.664824">Uniprocessor Garbage Collection Techniques</a></h3>
<p>到 1992 年，三十年的 GC 研究已经产生了许多想法，但缺乏统一的词汇。Wilson 的综述论文将这一切组织了起来。它不是一种新算法，而是一个分类学，为散落在几十年论文中的思想赋予了名称和结构。</p>
<p>Wilson 正式确立了所有后续算法构建其上的三种经典算法。</p>
<p>第一种是 <strong>mark-and-sweep</strong>（标记-清除），即 McCarthy 的原始算法。从 roots 开始，遍历对象图，标记你能触达的所有内容，然后扫过堆并释放任何未标记的内容。它自然处理循环引用，实现简单。缺点是经过足够多的分配和回收循环后，堆会变得 fragmented（碎片化）。存活对象最终散落在各处，中间夹杂着细小的空闲间隙，分配器(allocator)必须更费力地寻找空间。</p>
<p>第二种是 <strong>copying</strong>（复制算法），有时被称为 semi-space（半空间）。其想法是将堆分成两个相等的部分。你在其中一半进行分配，当它填满时，将所有存活对象拷贝到另一半，然后将第一半完全丢弃。碎片消失了，因为存活对象在拷贝过程中被紧密排列在一起。分配速度很快，因为你只需移动一个 bump pointer（碰撞指针）。代价是有一半的内存始终处于空闲状态，等待成为下一次拷贝的目标。</p>
<p>第三种是 <strong>reference counting</strong>（引用计数）。每个对象都记录有多少个指针指向它。当创建一个新引用时，计数增加；当移除一个引用时，计数减少。当计数归零时，对象立即被释放。没有追踪过程，没有停顿，销毁是确定性的。问题在于 cycles（循环引用）。如果两个对象相互指向，即使程序中没有任何其他部分可以触达它们，它们的计数也至少为 1。仅靠引用计数，它们永远不会被释放。</p>
<p>除了这三种算法，Wilson 还探讨了现代垃圾回收器赖以生存的两个观察结果。</p>
<p>第一个是 <strong>generational hypothesis</strong>（分代假说）：大多数对象死得早。在实践中，程序分配的临时对象（中间值、请求作用域的缓冲区、循环变量）往往很快变成垃圾，而只有一小部分对象会贯穿整个程序生命周期。如果你频繁回收年轻对象，偶尔回收老对象，你就能将大部分工作集中在堆中主要是垃圾的部分，这比每次都扫描所有内容的代价要小得多。</p>
<p>第二个是 <strong>tricolor marking</strong>（三色标记），这是一种用于增量和并发收集的抽象。你不再简单地将对象标记为已访问或未访问，而是使用三种颜色：white（白色，尚未见到）、grey（灰色，已见到但子节点尚未扫描）和 black（黑色，已完全处理）。收集器一次处理一个灰色对象。结束时，白色对象即为垃圾。这种抽象使得收集器和应用程序可以同时运行，而不会破坏彼此对堆的视图。Go 的并发 mark-and-sweep 和 ZGC 的并发标记都是这一思想的直接后裔。</p>
<p>本文“现代 GC”部分中的所有内容都可以映射回 Wilson 的分类。工程实现已经变得更加复杂，但底层结构依然如故。</p>
<h2>两种基本方法</h2>
<p>几乎所有的垃圾回收器要么是 reference counting（引用计数），要么是 tracing（追踪），或者是两者的某种结合。Wilson 的论文围绕这一划分进行组织，三十年后依然成立。</p>
<h3>Reference Counting (引用计数)</h3>
<p>每个对象维护一个指向它的引用计数。当引用创建时，计数增加。当引用移除时，计数减少。当计数归零时，对象立即被释放。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-2.png" alt="" /></p>
<p>这是 CPython 所使用的其主要机制。它很简单，并能提供确定性的销毁。当指向文件句柄的最后一个引用消失时，<strong>del</strong> 运行，文件当场关闭，而不是在以后的某个 GC cycle中。</p>
<p>有两个问题使得引用计数无法独立胜任。</p>
<p><strong>Cycles (循环引用)。</strong> 如果对象 A 指向对象 B，且对象 B 指向 A，那么即使程序中没有任何其他部分能触达它们，两者的计数也至少为 1。两者都不会被释放。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-3.png" alt="" /></p>
<p>这并非理论上的边缘案例。循环引用在链表数据结构、父子关系、观察者模式和缓存中自然出现。稍后在介绍 CPython 的 GC 时，我将讨论 Python 如何处理这个问题。</p>
<p><strong>Per-mutation overhead (每次修改的开销)。</strong> 每次指针赋值都需要更新引用计数。在多线程程序中，这些必须是 atomic（原子）操作，成本昂贵得多。每当你将对象传递给函数、返回它或将其赋值给字段时，你都要支付这种代价。</p>
<h3>Tracing (追踪式，即 Mark-and-Sweep)</h3>
<p>追踪式收集器不跟踪单个引用，而是从一组已知的存活引用（称为 root set，根集合）开始，遍历整个对象图。它能触达的每个对象都被标记为存活。其他所有对象都被释放。</p>
<p>Root set 是起点，因此什么算作 root（根）至关重要。不同语言的答案是相同的：root 是 runtime（运行时）无需追踪就能找到的任何引用。这些指针锚定在程序当前的执行状态中，是在任何遍历开始之前你就知道是存活的东西。</p>
<p>在实践中，roots 分为以下几类。</p>
<p>每个活跃 stack frame（栈帧）中的 <strong>local variables</strong>（局部变量）和函数参数都是 roots。程序正在活跃地运行这些函数，因此它们引用的任何内容定义上都是在使用中的。</p>
<p><strong>Global and static variables</strong>（全局变量和静态变量）是 roots，因为它们在程序的整个生命周期内都存在。</p>
<p><strong>CPU registers</strong>（CPU 寄存器）是 roots。因为当 JIT 编译器优化一个热点方法时，它可能会将频繁访问的对象引用保留在 CPU 寄存器中，而不是写回栈。如果 GC 此时运行，寄存器保存着该对象的唯一存活引用。如果 GC 不扫描寄存器，它就会释放一个仍在使用中的对象。为了防止这种情况，运行时在代码中定义了 safe points（安全点），GC 只能在这些点发生，并且在这些点，它会快照寄存器状态以寻找持有的任何引用。</p>
<p><strong>Runtime（运行时）本身</strong>也持有与用户代码无关的 roots。在 JVM 中，class loaders 是 roots：你加载的每个类都由其类加载器引用，只要类加载器存活，它加载的每个类（包括它们的静态字段）就保持存活。Interned strings（常量池字符串）是 roots，因为 String.intern() 将字符串存储在 JVM 维护的共享池中。JNI handles 是 roots，因为当原生 C 或 C++ 代码通过 Java Native Interface 持有 Java 对象的引用时，该引用存在于 Java 堆外的句柄表中，GC 必须扫描它。每个活跃线程都是一个 root，其整个调用栈帧都是 root set 的一部分。</p>
<p>Go 的运行时遵循同样的原则。每个 goroutine 都有自己的栈，必须扫描所有 goroutine 栈以寻找 roots。运行时还跟踪自己的内部数据结构，例如 finalizer 队列，作为 root set 的一部分。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-4.png" alt="" /></p>
<p>核心见解是：roots 是由运行时在无需追踪的情况下就已经知道是存活的东西定义的。其他所有东西必须通过从 root 可达来证明自己的生存权。这就是为什么这个概念是与语言无关的。Java、Go 和 Python 之间的具体 roots 集合有所不同，但原则是一样的：从你知道是存活的地方开始，向外追踪，并回收其余部分。</p>
<p>循环引用被自然处理。如果 A 和 B 相互指向，但都无法从任何 root 到达，则标记阶段永远不会访问它们。它们保持未标记状态并被清除。</p>
<p>代价：朴素的 mark-and-sweep 必须在追踪堆时暂停整个程序。这种 stop-the-world（全线停顿）是早期垃圾回收器的核心问题，也是现代 GC 几十年来工程化改进的重点。</p>
<h3>为什么大多数现代 GC 都是追踪式的</h3>
<p>在具有高分配速率的服务器工作负载中，引用计数的逐次修改成本会积少成多。每次指针写入都会增减计数。在多线程程序中，这些更新必须是原子的，而原子操作很昂贵。在数十个线程中每秒进行数千次分配时，这种开销变得可衡量。此外，循环引用问题无论如何都需要一个补充的追踪步骤。而且追踪式收集器可以做成并发的，在应用程序运行的同时运行，只有简短的停顿。</p>
<p>Java 和 Go 使用追踪式收集器。Python 是一个显著的例外，它以引用计数为基础，并在此之上增加了一层用于追踪循环引用的检测器。</p>
<h2>追踪式的变体</h2>
<p>Wilson 的论文描述了实现追踪的四种方式，每种方式都有不同的权衡。</p>
<h3>Mark-Sweep (标记-清除)</h3>
<p>最简单的追踪式收集器。分为两个阶段：</p>
<ol>
<li><strong>Mark (标记)：</strong> 从 roots 开始，遍历对象图并在每个可达对象上设置标记位。</li>
<li><strong>Sweep (清除)：</strong> 遍历整个堆。任何没有标记位的对象都是垃圾。释放它并将内存添加回空闲列表。</li>
</ol>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-5.png" alt="" /></p>
<p>Mark-sweep 的主要问题是 fragmentation（碎片化）。经过足够的回收周期后，堆看起来就像瑞士奶酪：存活对象散布其间，中间有很小的空闲间隙。你总共可能有 100MB 空闲内存，但没有一个连续的块大到足以满足一次新分配。分配器必须维护一个 free list 并搜索合适的空间，随着堆变得碎片化，这会变慢。</p>
<h3>Copying (Semi-Space，复制算法/半空间)</h3>
<p>堆被分成两个相等的一半：from-space（源空间）和 to-space（目标空间）。分配发生在 from-space，使用简单的 bump pointer（碰撞指针）。当 from-space 填满时，收集器将所有存活对象拷贝到 to-space，更新所有指针，然后交换两者的角色。旧的 from-space 被完全丢弃。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-6.png" alt="" /></p>
<p>分配速度极快，因为它只是一个指针移动。Compaction（压缩）自然发生。代价是任何时候只有一半的堆可用。</p>
<h3>Mark-Compact (标记-整理)</h3>
<p>标记阶段与 mark-sweep 相同，但收集器不是简单地释放未标记的对象，而是将所有存活对象滑动到堆的一端。这消除了碎片，且没有复制算法 50% 的内存开销。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-7.png" alt="" /></p>
<p>缺点是整理需要对堆进行多次扫描：一次标记，一次计算新地址，一次更新所有指针，一次移动对象。</p>
<h3>The Generational Hypothesis (分代假说)</h3>
<p>Wilson 论文中最具影响力的观察之一是弱分代假说：大多数对象死得早。</p>
<p>在典型的 Web 服务器中，每个请求都会创建临时对象（解析器、中间字符串、响应构建器），它们只存活几毫秒。配置对象、连接池和缓存则贯穿整个应用程序生命周期。</p>
<p>分代收集器利用这一点，将堆划分为 generations（代）。新对象进入 young generation（年轻代）。如果它们在几次回收中幸存下来，就会被提升到 old generation（老年代）。年轻代回收频繁且速度快，因为那里的大多数对象已经死了。老年代回收较少发生。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-8.png" alt="" /></p>
<p><strong>Eden</strong> 是所有新对象出生的地方。每一个 new Object() 都去这里。它很快就会填满，因为大多数程序分配速率很高。</p>
<p><strong>S0 和 S1</strong> 是两个较小的 survivor spaces（幸存者空间）。当 Eden 填满并运行 minor GC（次要回收）时，收集器将 Eden 中的每个存活对象拷贝到其中一个空间（比如 S0）。下一次回收时，来自 Eden 和 S0 的幸存者被拷贝到 S1。再下一次，回到 S0。它们在每个周期轮换。这是年轻代中的复制算法：没有碎片，没有空闲列表，只有两半空间轮流充当目标。代价是你需要两个幸存者空间，但它们保持得很小，因为到回收运行时，Eden 中的大多数对象都已经死了。</p>
<p><strong>Promotion to old generation (提升到老年代)。</strong> 在对象在 S0 和 S1 之间反弹足够多次之后（JVM 中的默认阈值是 15 次），收集器认定它已赢得了一席之地，并将其提升到老年代。老年代回收频率低得多，并且使用更重的算法（标记-整理而非复制），因为那里的对象庞大且长寿。</p>
<p>关键的实现挑战是跟踪从老对象到新对象的引用。如果一个老对象指向一个年轻对象，即使没有年轻代 root 指向它，该年轻对象也绝不能被回收。这通过 write barrier（写屏障）解决，即在每次指针写入时注入的一小段代码，用于在 remembered set（记录集）中记录跨代引用。</p>
<h2>用 Go 构建一个玩具级 Mark-and-Sweep GC</h2>
<p>我写了一个极简的 mark-and-sweep 收集器来使这些概念具体化。它大约有 70 行代码，演示了完整循环：分配对象、构建对象图、从 roots 标记以及清除不可达对象。</p>
<pre><code>package main

import "fmt"

// Object 代表一个在堆上分配的对象。
type Object struct {
    name     string
    marked   bool
    children []*Object
}

// VM 是一个带有垃圾回收器的微型虚拟机。
type VM struct {
    heap  []*Object
    roots []*Object // 模拟栈变量和全局变量
}

// NewObject 在 VM 的堆上分配一个对象。
func (vm *VM) NewObject(name string) *Object {
    obj := &amp;Object{name: name}
    vm.heap = append(vm.heap, obj)
    return obj
}

// mark 从每个 root 开始遍历并标记所有可达对象。
func (vm *VM) mark() {
    for _, root := range vm.roots {
        vm.markObject(root)
    }
}

func (vm *VM) markObject(obj *Object) {
    if obj == nil || obj.marked {
        return
    }
    obj.marked = true
    for _, child := range obj.children {
        vm.markObject(child)
    }
}

// sweep 释放未标记的对象并重置幸存者的标记。
func (vm *VM) sweep() {
    alive := []*Object{}
    for _, obj := range vm.heap {
        if obj.marked {
            obj.marked = false // 为下一个 GC 周期重置
            alive = append(alive, obj)
        } else {
            fmt.Printf("  collected: %s\n", obj.name)
        }
    }
    vm.heap = alive
}

// GC 运行一次完整的 mark-and-sweep 回收。
func (vm *VM) GC() {
    fmt.Printf("gc: heap has %d objects\n", len(vm.heap))
    vm.mark()
    vm.sweep()
    fmt.Printf("gc: %d objects remain\n\n", len(vm.heap))
}

func main() {
    vm := &amp;VM{}

    a := vm.NewObject("A")
    b := vm.NewObject("B")
    c := vm.NewObject("C")
    _ = vm.NewObject("D") // 已分配但从未链接到任何东西

    // 构建图: A -&gt; B -&gt; C
    a.children = append(a.children, b)
    b.children = append(b.children, c)

    // 只有 A 是 root
    vm.roots = append(vm.roots, a)

    fmt.Println("=== GC #1: D is unreachable ===")
    vm.GC()

    // 创建循环: C -&gt; A, 然后移除所有 roots
    c.children = append(c.children, a)
    vm.roots = nil

    fmt.Println("=== GC #2: A-&gt;B-&gt;C-&gt;A cycle, no roots ===")
    vm.GC()
}
</code></pre>
<p>运行结果：</p>
<pre><code>=== GC #1: D is unreachable ===
gc: heap has 4 objects
  collected: D
gc: 3 objects remain

=== GC #2: A-&gt;B-&gt;C-&gt;A cycle, no roots ===
gc: heap has 3 objects
  collected: A
  collected: B
  collected: C
gc: 0 objects remain
</code></pre>
<p>第一次回收：A、B 和 C 通过 root A 可达。D 没有任何 root 路径，因此被回收。</p>
<p>第二次回收：A、B 和 C 形成了一个循环（A->B->C->A），但没有 roots。标记阶段从未访问过它们中的任何一个。所有三个都被清除了。这正是击败引用计数的场景。循环中的每个对象都有非零的引用计数，但没有一个能从 root 到达。</p>
<p><strong>追踪式 GC 不关心循环。它们只关心从 roots 开始的可达性。</strong></p>
<p>有一点需要注意：markObject 函数使用了递归，这在深层对象图上会耗尽栈空间。真实的垃圾回收器使用显式的 worklist（工作列表）而不是调用栈。</p>
<h2>现代 GC 实现</h2>
<p>上面的玩具收集器为了整个标记和清除过程停止了世界。现代 GC 已经进化到在应用程序持续运行的同时并发完成大部分工作。</p>
<h3>Go: 三色并发标记-清除 (Tri-Color Concurrent Mark-and-Sweep)</h3>
<p>Go 的垃圾回收器是非分代的、非整理的且并发的。它不按年龄区分对象，也不在内存中移动对象。其重点是保持低停顿时间。</p>
<p>收集器使用三色抽象（tri-color abstraction）进行并发标记。每个对象处于三种状态之一：</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-9.png" alt="" /></p>
<ul>
<li><strong>White (白色)</strong>: 尚未访问。标记结束时仍为白色的任何东西都是垃圾。</li>
<li><strong>Grey (灰色)</strong>: 已访问，但其子节点尚未全部扫描。遍历的前沿（frontier）。</li>
<li><strong>Black (黑色)</strong>: 已访问，所有子节点已扫描。确定存活。</li>
</ul>
<p>收集器开始时将所有对象设为白色，然后将 roots 设为灰色，并处理灰色对象直到不再剩余。所有仍为白色的内容都被清除。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-10.png" alt="" /></p>
<pre><code>开始: 所有对象为白色，roots 为灰色

步骤 1: 选取一个灰色对象，扫描其子节点
        - 将子节点标为灰色
        - 将扫描过的对象标为黑色

步骤 2: 重复直到没有灰色对象剩余

步骤 3: 所有白色对象都是垃圾

示例:

  Roots: [A]

  开始:      A(grey) --&gt; B(white) --&gt; D(white)
             A(grey) --&gt; C(white)

  扫描 A:    A(black) --&gt; B(grey) --&gt; D(white)
             A(black) --&gt; C(grey)

  扫描 B:    A(black) --&gt; B(black) --&gt; D(grey)
             A(black) --&gt; C(grey)

  扫描 C:    A(black) --&gt; B(black) --&gt; D(grey)
             A(black) --&gt; C(black)

  扫描 D:    A(black) --&gt; B(black) --&gt; D(black)
             A(black) --&gt; C(black)

  结果: 任何剩余的白色对象都是垃圾并被释放
</code></pre>
<p>难点在于应用程序在收集器遍历时持续运行并修改指针。这造成了一个需要仔细处理的正确性问题。</p>
<p>收集器认为黑色对象已完成。一旦对象变黑，收集器就不会再扫描它。它的所有子节点都已被访问并设为灰色。但是，如果应用程序在收集器仍在运行时，将一个指向白色对象的指针写入黑色对象，收集器就有麻烦了。黑色对象已经处理完了。该白色对象也无法从任何灰色对象触达。当标记阶段结束并清除运行时，该白色对象将被释放，即便有一个存活的黑色对象指向它。</p>
<p>这被称为 <strong>tricolor invariant</strong>（三色不变性）：黑色对象绝不能直接指向白色对象。如果发生了这种情况，白色对象对收集器是不可见的，会被错误释放。write barrier（写屏障）的存在专门用于在并发标记期间应用程序修改对象图时维护这一不变性。</p>
<p>Go 通过 <strong>hybrid write barrier</strong>（混合写屏障，Go 1.8 引入）解决了这个问题。要理解它为什么有效，看看它结合的两种旧屏障会有所帮助。</p>
<p><strong>Dijkstra’s 插入屏障 (1978)</strong>：每当一个指针被写入对象时，将新的被引用者设为灰色。如果一个黑色对象存储了对白色对象的引用，该白色对象会在收集器错过它之前变灰。这维护了三色不变性。</p>
<p>问题在于 goroutine 栈与堆对象不同。编译器在堆指针写入处注入写屏障，例如写入结构体字段或切片元素。栈写入是局部变量赋值，编译器对其分别处理。在每一个局部变量赋值上放屏障会使函数调用和基本操作变得极其昂贵，所以屏障不覆盖它们。这意味着在并发标记期间，goroutine 可以自由地将指向白色对象的指针写入局部变量，而没有屏障触发。收集器不知道发生了这事。</p>
<p>为了修复这一点，在并发标记结束时，Go 曾经必须停止世界并从头重新扫描每个 goroutine 的整个栈。重新扫描时发现的任何指向白色对象的指针都会变灰，防止它们被错误释放。此步骤的停顿时间随着 goroutine 数量和其栈大小而增加。拥有成千上万个 goroutine 的程序可能会看到数毫秒的 STW 停顿，仅仅是为了这次重新扫描。这是 Go 1.8 之前主要的 STW 停顿来源。</p>
<p><strong>Yuasa’s 删除屏障 (1990)</strong> 采取相反的方法：每当一个指针即将被覆盖时，在旧引用消失前将其变灰。这确保了在标记开始时可达的任何东西直到结束都保持可达，即便应用程序在标记期间丢弃了它的引用。缺点是标记期间死亡的一些对象会存活到下一个周期（floating garbage，浮动垃圾），因为屏障保守地让它们活着。</p>
<p><strong>Go 的混合屏障</strong>结合了两者。在堆写入时，它同时应用两种屏障：将旧引用变灰（Yuasa）并将新引用变灰（Dijkstra）。在栈写入时，不运行屏障，但栈上新分配的对象开始时就是黑色而不是白色。这种组合赋予了收集器足够强的不变性，使其在标记结束时永远不需要重新扫描栈。STW 停顿从几十毫秒降到了不到一毫秒。</p>
<pre><code>// 混合屏障在堆指针写入时的逻辑:
// *slot = new_ptr

shade(*slot)   // 将旧引用变灰 (Yuasa: 不要丢掉之前在那里的内容)
shade(new_ptr) // 将新引用变灰 (Dijkstra: 不要错过新到来的内容)
*slot = new_ptr
</code></pre>
<p>这就是并发垃圾回收的吞吐量成本：标记阶段的每一次堆指针写入都要运行此 shade 逻辑。单次操作开销虽小，但在高分配速率下会累积。权衡的结果是你获得了亚毫秒级的 STW 停顿，而不是几十毫秒。</p>
<p>Go 仅简短地停止世界以扫描 goroutine 栈并切换写屏障的开关。实际的标记和清除与应用程序并发进行。</p>
<p><strong>No compaction (无整理)。</strong> Go 在分配后不移动对象。相反，Go 使用 tcmalloc 风格的分配器，将内存划分为 size classes（大小类），并从每个处理器的缓存（per-processor caches）中分配。对象被分组为固定的大小类（8 字节、16 字节、32 字节，最高达 32 KB）。分配时从空闲列表中选取合适大小的槽。这减少了碎片而无需移动对象，但并不能完全消除碎片。</p>
<p><strong>No generational collection (无分代收集)。</strong> Go 团队的理由是，考虑到 Go 典型的带有 goroutine 和并发工作负载的分配模式，分代 GC 增加的复杂性（用于跟踪老到新指针的写屏障、提升逻辑、分代大小调优）带来的收益是不确定的。Go 通过使其并发标记器足够快来补偿，从而使额外的回收频率变得可以接受。</p>
<p><strong>关键里程碑：</strong></p>
<ul>
<li>Go 1.5 (2015)：引入并发 GC。在此之前，Go 使用全停顿收集器，停顿时间达 10-100ms 或更多。此版本使 Go 能够胜任延迟敏感型服务。</li>
<li>Go 1.8 (2017)：混合写屏障。降低了在并发标记期间维护三色不变性的开销。</li>
<li>Go 1.19 (2022)：GOMEMLIMIT。使 Go 程序能在容器环境的内存预算内工作。</li>
</ul>
<p><strong>GOGC 调节旋钮。</strong> Go 提供了一个主要的调优参数：GOGC。它控制在下一次 GC 触发之前堆可以增长多少。默认值是 100，意味着当堆自上次回收以来翻倍时触发 GC。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-11.png" alt="" /></p>
<pre><code>GOGC=100 (默认):
  GC 后，存活堆 = 500MB
  下次 GC 触发点: 500MB * (1 + 100/100) = 1000MB

GOGC=50 (更激进):
  GC 后，存活堆 = 500MB
  下次 GC 触发点: 500MB * (1 + 50/100) = 750MB

GOGC=200 (较保守):
  GC 后，存活堆 = 500MB
  下次 GC 触发点: 500MB * (1 + 200/100) = 1500MB
</code></pre>
<p>更低的 GOGC 意味着更频繁的回收（更低的内存占用，更高的 CPU 开销）。更高的 GOGC 意味着较少的回收（更高的内存占用，更低的 CPU 开销）。</p>
<p>Go 1.19 增加了 GOMEMLIMIT，这是一个软内存限制。在具有硬性内存预算的容器环境中，GOMEMLIMIT 告诉 GC pacer（步调算法）在内存使用接近限制时变得更加激进。</p>
<p><strong>亲自尝试：</strong></p>
<pre><code>package main

import (
    "fmt"
    "runtime"
    "time"
)

var longLived []*[1024 * 1024]byte

func main() {
    fmt.Println("Go version:", runtime.Version())

    for round := 0; round &lt; 50; round++ {
        // 短寿对象: 分配小对象，让它们死亡
        for i := 0; i &lt; 5000; i++ {
            _ = make([]byte, 1024)
        }

        // 长寿对象: 每 10 轮保留一个
        if round%10 == 0 {
            arr := new([1024 * 1024]byte)
            longLived = append(longLived, arr)
        }

        time.Sleep(50 * time.Millisecond)
    }

    var stats runtime.MemStats
    runtime.ReadMemStats(&amp;stats)
    fmt.Printf("Total GC cycles: %d\n", stats.NumGC)
    fmt.Printf("Total STW pause: %v\n", time.Duration(stats.PauseTotalNs))
    fmt.Printf("Long-lived objects: %d\n", len(longLived))
}
</code></pre>
<p>运行并开启 GC 追踪：</p>
<pre><code>GODEBUG=gctrace=1 go run gcdemo.go
</code></pre>
<p>观察输出内容：</p>
<pre><code>gc 1 @0.011s 1%: 0.044+0.56+0.13 ms clock, 0.62+0.21/0.57/0+1.8 ms cpu, 3-&gt;4-&gt;0 MB, 4 MB goal, 0 MB stacks, 0 MB globals, 14 P
</code></pre>
<p>从左到右阅读：</p>
<ul>
<li>gc 1: GC 周期编号</li>
<li>@0.011s: 自程序启动的时间</li>
<li>1%: 到目前为止 GC 消耗的 CPU 百分比</li>
<li>
<p>0.044+0.56+0.13 ms clock: GC 周期的三个阶段：STW 标记开始 (0.044ms) + 并发标记和扫描 (0.56ms) + STW 标记结束 (0.13ms)。STW 停顿是 clock 字段中的第一个和第三个数字。在此例中，应用程序被冻结的总墙钟时间是 0.044 + 0.13 = 0.174ms。中间的 0.56ms 是并发的：你的应用程序一直在运行。在 Go 中，STW 停顿通常在 1ms 以下，往往远低于 0.1ms。</p>
</li>
<li>
<p>0.62+0.21/0.57/0+1.8 ms cpu: CPU 时间细目。格式为：STW-开始 + 辅助/背景/空闲 + STW-结束。每个数字代表：</p>
<ul>
<li>0.62ms — STW 标记开始时所有核心的 CPU 总时间。高于墙钟时间 (0.044ms)，因为 Go 会在多个核心上并行化初始栈扫描。</li>
<li>0.21ms — 应用程序 goroutine 执行 mutator assists（赋值器辅助）所花费的 CPU 时间。当某个 goroutine 分配速度超过 GC 处理速度时，它会被“征税”，必须在允许其分配之前自己做一些标记工作。</li>
<li>0.57ms — 专用背景 GC 工作 goroutine 执行并发标记所使用的 CPU 时间。</li>
<li>0 — 空闲 GC 工作者的 CPU 时间（仅在调度器没有其他任务运行时才领取 GC 任务的 goroutine）。此处为零意味着专用工作者处理了所有事情。</li>
<li>1.8ms — STW 标记结束时所有核心的 CPU 总时间。高于墙钟 (0.13ms)，因为多个核心并行工作以排空剩余任务并禁用写屏障。</li>
</ul>
</li>
</ul>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-12.png" alt="" /></p>
<p>当多个核心并行工作时，CPU 时间可以超过墙钟时间。并发阶段的 CPU 时间可能少于墙钟时间，因为 GC 与你的应用程序共享核心。</p>
<ul>
<li>3->4->0 MB: GC 开始时的堆大小、GC 触发点的堆大小、GC 完成后的存活堆大小</li>
<li>4 MB goal: 下次 GC 触发前的目标堆大小（基于 GOGC 和当前存活堆）</li>
<li>0 MB stacks: goroutine 栈使用的内存</li>
<li>0 MB globals: 标记期间扫描的全局变量使用的内存</li>
<li>14 P: 逻辑处理器数量 (GOMAXPROCS)</li>
</ul>
<h3>Java: G1GC (Garbage First Collector)</h3>
<p>G1GC 自 JDK 9 以来一直是 Java 的默认垃圾回收器。它是一个分代的、基于区域（region）的收集器。它进行追踪、标记和整理，但它是增量式进行的，而不是一次性完成。</p>
<p><strong>Region layout (区域布局)。</strong> G1 将堆划分为大小相等的区域，通常每个区域为 1MB 到 32MB，取决于堆的大小。每个区域在任何时候扮演四种角色之一：Eden（伊甸园）、Survivor（幸存者）、Old（老年代）或 Humongous（巨型对象，用于超过半个区域大小的对象）。区域的角色可以在不同回收周期之间改变。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-13.png" alt="" /></p>
<p><strong>Young collection (次要 GC)。</strong> Eden 区域填满。G1 停止世界，使用并行多线程标记器标记 Eden 和 Survivor 区域中的存活对象，将幸存者拷贝到新的 Survivor 区域或提升到 Old 区域，并完全丢弃旧的 Eden 区域。这是一个并行的 STW 停顿，但很短，因为年轻代区域较小且年轻对象大多已死。</p>
<p><strong>Mixed collection (混合回收)。</strong> G1 周期性地运行并发标记周期，以找出哪些老年代区域包含的垃圾最多。然后运行混合回收：同时疏散（evacuating）年轻代区域和最具“盈利价值”的老年代区域。这就是“Garbage First”名称的由来。G1 总是优先选取垃圾密度最高的老年代区域，从而在单位停顿时间内实现最大的回收量。</p>
<p><strong>SATB (Snapshot-At-The-Beginning，起始快照)。</strong> 在并发标记期间，应用程序持续运行并修改对象图。G1 使用 SATB 维护正确性。在标记开始时，G1 对哪些对象存活进行逻辑快照。该快照中存活的对象在此周期被视为存活，即使应用程序在标记期间丢弃了它们。写屏障将修改字段的旧值记录到 SATB 队列中。这种做法是保守的（一些垃圾会存活到下个周期），但是正确的。</p>
<pre><code>并发标记正在运行。应用程序执行：
  obj.field = null   (原本指向 X)

没有 SATB: X 可能没有其他引用，未被标记，在使用中被释放。
有 SATB:    写屏障记录“此处曾有 X”，将 X 标为灰色。安全。
</code></pre>
<p><strong>Pause target (停顿目标)。</strong> 你可以通过 -XX:MaxGCPauseMillis 配置 G1 的目标最大停顿时间。默认值是 200ms。G1 通过调整区域数量、回收集合大小和时机，尝试将停顿保持在目标范围内。它并不总是能成功，特别是在 Full GC 期间，但它是主要的调优旋钮。</p>
<p><strong>亲自尝试：</strong></p>
<pre><code>import java.util.ArrayList;
import java.util.List;

public class GCDemo {
  static List&lt;byte[]&gt; longLived = new ArrayList&lt;&gt;();

  public static void main(String[] args) throws InterruptedException {
    System.out.println("Starting GC demo...");

    for (int round = 0; round &lt; 50; round++) {
      // 短寿对象：创建并立即丢弃
      for (int i = 0; i &lt; 1000; i++) {
        byte[] tmp = new byte[10 * 1024]; // 每个 10KB
      }

      // 长寿对象：保留一些对象以构建老年代
      if (round % 5 == 0) {
        longLived.add(new byte[1024 * 1024]); // 1MB
      }

      Thread.sleep(50);
    }

    System.out.println("Done. Long-lived objects: " + longLived.size());
  }
}
</code></pre>
<p>使用 G1GC 日志运行：</p>
<pre><code># 编译
javac GCDemo.java

# 使用 G1GC (Java 9+ 默认) 并开启 GC 日志
java -Xmx256m \
     -XX:+UseG1GC \
     "-Xlog:gc*:file=gc_g1.log:time,uptime,level,tags" \
     GCDemo

# 或者，使用简洁的一行输出
java -Xmx256m -Xlog:gc GCDemo
</code></pre>
<p>观察日志：</p>
<pre><code>[0.005s][info][gc] Using G1
[0.135s][info][gc] GC(0) Pause Young (Normal) (G1 Evacuation Pause) 26M-&gt;3M(256M) 0.644ms
[0.812s][info][gc] GC(1) Pause Young (Normal) (G1 Evacuation Pause) 132M-&gt;7M(256M) 0.707ms
[1.710s][info][gc] GC(2) Pause Young (Normal) (G1 Evacuation Pause) 165M-&gt;13M(256M) 1.019ms
[2.528s][info][gc] GC(3) Pause Young (Normal) (G1 Evacuation Pause) 171M-&gt;19M(256M) 0.964ms
</code></pre>
<p>阅读日志：</p>
<ul>
<li>Using G1: 确认 G1GC 是活跃收集器</li>
<li>Pause Young (Normal): 回收 Eden 和 Survivor 区域的次要 GC</li>
<li>G1 Evacuation Pause: G1 正在将存活对象从回收区域拷贝（疏散）到新区域</li>
<li>26M->3M(256M) 0.644ms: 堆之前是 26MB，之后是 3MB，总堆容量 256MB，停顿耗时 0.644ms</li>
<li>在 2.5 秒的运行时中进行了四个 GC 周期，每个周期在 1.1ms 内完成。大多数分配的对象都是短寿的，并在年轻代被回收。</li>
</ul>
<h3>Java: ZGC (Z Garbage Collector)</h3>
<p>ZGC 自 Java 11 起可用，并在 Java 15 中达到生产就绪状态。扩展了分代收集的 Generational ZGC 在 Java 21 中引入。ZGC 的目标是无论堆大小如何（包括数百 GB 的堆），停顿时间均保持在亚毫秒级。</p>
<p>G1 在年轻代回收时停顿较短，但随着堆的增长，在并发标记设置和混合回收期间会有更长的停顿。ZGC 的方法不同：它几乎将所有工作（标记、重定位、引用处理）并发进行，将 STW 工作降至最低。</p>
<p><strong>Colored pointers (有色指针)。</strong> ZGC 直接在指针位中编码 GC 元数据。在 64 位平台上，指针宽度为 64 位，但你实际上并不需要所有 64 位来寻址内存。2^42 就能给你 4TB 的可寻址空间，这超出了大多数应用程序的使用范围。这使得每个指针中留有超过 20 位空闲。ZGC 重新利用其中一些空闲位，直接在指针内部存储 GC 状态。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-14.png" alt="" /></p>
<p>每个元数据位都有特定用途：</p>
<ul>
<li>
<p><strong>M0 和 M1 (标记位)：</strong> 用于跟踪对象是否已被标记为存活。ZGC 在每个 GC 周期中交替使用 M0 和 M1。在周期 1，收集器对每个可达对象设置 M0。在周期 2，它改用 M1。这样收集器就能区分“本周期标记”和“上个周期标记”，而无需在周期之间清除所有标记位。</p>
</li>
<li>
<p><strong>Remap (R，重映射)：</strong> 此位跟踪在对象重定位（relocated）后指针是否已更新。在并发重定位期间，ZGC 将对象移动到新地址，但并不立即更新堆中的每一个指针。相反，它保留旧指针，并使 remap 位处于未设置状态。当应用程序加载这些过时指针之一时，load barrier（读屏障/加载屏障）会注意到 remap 位未设置，并对其进行修正。</p>
</li>
<li>
<p><strong>Finalizable (F)：</strong> 表示该对象具有一个需要在释放前运行的 finalizer。</p>
</li>
</ul>
<p>巧妙之处在于元数据随指针移动。GC 不需要一个单独的侧表来查找对象的 GC 状态。每个指针都已经携带了它。</p>
<p><strong>Load barriers (加载屏障)。</strong> 每次应用程序从堆加载引用时，ZGC 都会插入一个加载屏障。屏障检查指针的颜色位，如果它们不处于预期状态，则采取行动。</p>
<p>以下是实际操作中的情况。假设收集器在并发重定位阶段将一个对象从地址 0&#215;1000 移动到了 0&#215;2000。应用程序仍然持有一个地址为 0&#215;1000 且 remap 位未设置的指针。</p>
<pre><code>应用程序代码:
  Object x = obj.field;

实际执行的内容:
  raw_ptr = load obj.field           // raw_ptr = 0x1000, remap bit = 0
  if (raw_ptr.color != expected) {   // remap bit 为 0, expected 为 1 → 进入 slow path
      new_addr = forwarding_table[0x1000]  // 查找: 对象已移动到 0x2000
      raw_ptr = set_address(raw_ptr, 0x2000)
      raw_ptr = set_remap_bit(raw_ptr)
      obj.field = raw_ptr            // 就地修正指针，以便下次使用
  }
  x = raw_ptr                       // x 现在指向 0x2000
</code></pre>
<p>下次任何线程加载 obj.field 时，remap 位已经设置好了。屏障检查通过 fast path，没有额外工作。过时指针在第一次访问时被惰性修正。</p>
<p>这是关键机制。与其像 G1 在疏散期间那样让 GC 停止世界以一次性更新所有指向重定位对象的指针，ZGC 让应用程序在遇到指针时逐个修正。代价是每次指针加载都要支付屏障检查的开销，即便没有任何东西被重定位。在实践中，fast path（检查几位）执行代价足够小，与避免 STW 重定位停顿带来的收益相比，开销很小。</p>
<p><strong>Concurrent relocation (并发重定位)。</strong> G1 停止世界以将存活对象从回收区域中疏散。ZGC 在应用程序运行的同时重定位对象。它能做到这一点是因为加载屏障处理了指针修正。在启动和结束每个阶段（标记开始、标记结束、重定位开始）时有简短的 STW 停顿，但这些通常远低于 1ms。拷贝对象和修正指针的实际工作是并发发生的。</p>
<p><strong>Generational ZGC (Java 21+)。</strong> 最初的 ZGC 不按年龄划分堆。分代 ZGC 增加了年轻代和老年代，同时保留了亚毫秒级停顿的保证。它更频繁地回收年轻区域（垃圾最多的地方），较少回收老年代区域。加载屏障和有色指针机制被扩展以处理分代写屏障。</p>
<p><strong>何时使用 ZGC vs G1：</strong></p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-15.png" alt="" /></p>
<p><strong>亲自尝试：</strong></p>
<pre><code># 使用 ZGC 运行
java -Xmx256m \
     -XX:+UseZGC \
     "-Xlog:gc*:file=gc_zgc.log:time,uptime,level,tags" \
     GCDemo

# 使用分代 ZGC (Java 21+)
java -Xmx256m \
     -XX:+UseZGC -XX:+ZGenerational \
     -Xlog:gc \
     GCDemo
</code></pre>
<p>观察日志：</p>
<pre><code>[0.318s] GC(0) Garbage Collection (Warmup) 28M(11%)-&gt;12M(5%)
[0.321s] GC(0) Pause Mark Start 0.023ms
[0.489s] GC(0) Concurrent Mark 168.123ms
[0.491s] GC(0) Pause Mark End 0.019ms
[0.492s] GC(0) Concurrent Select Relocation Set 1.234ms
[0.502s] GC(0) Concurrent Relocate 10.456ms
</code></pre>
<p>STW 停顿是标记为“Pause”的行。其他所有内容都是并发的。将此处的停顿持续时间与 G1 的输出进行对比。</p>
<h3>Python: 引用计数加循环 GC</h3>
<p>CPython（Python 的参考实现）是“追踪式收集器占主导”模式的主要例外。它使用引用计数作为主要机制，并在之上增加了一层用于追踪循环引用的检测器。</p>
<p><strong>CPython 中的引用计数。</strong></p>
<p>每个 Python 对象都有一个 ob_refcnt 字段。Python 的 C API 在 Py_INCREF 时增加，在 Py_DECREF 时减少。当计数归零时，对象在 _Py_Dealloc 中被立即释放。这赋予了 Python 确定性的销毁：<strong>del</strong> 方法和上下文管理器的 <strong>exit</strong> 调用在最后一个引用掉落的那一刻发生。</p>
<pre><code>import sys

x = []
print(sys.getrefcount(x))  # 2: 1个来自x，1个来自getrefcount参数本身的临时引用

y = x
print(sys.getrefcount(x))  # 3: 1个x, 1个y, 1个getrefcount参数

del y
print(sys.getrefcount(x))  # 2: 回到1个x, 1个getrefcount参数
</code></pre>
<p><strong>循环引用问题。</strong> 仅靠引用计数无法回收循环垃圾。</p>
<pre><code>import gc

# 创建循环引用
class Node:
    def __init__(self, name):
        self.name = name
        self.ref = None

a = Node("A")
b = Node("B")
a.ref = b
b.ref = a   # cycle: A -&gt; B -&gt; A

# a 和 b 的计数都 &gt;= 1（由于相互引用）。
# 仅靠引用计数，两者都不会被释放。

del a
del b
# a 和 b 依然存活！Refcount: A 为 1 (来自 b.ref), B 为 1 (来自 a.ref)

# 显式触发循环检测器
collected = gc.collect()
print(f"Collected {collected} objects")  # 收集了 4 个对象 (2个node + 2个dict)
</code></pre>
<p>引用计数处理了常见情况，但它无法收集循环引用。CPython 的答案是运行在引用计数系统之上的独立循环检测器。其实现在 Modules/gcmodule.c 中。</p>
<p>循环检测器是一个追踪式收集器，但它并不追踪整个堆。它仅跟踪能够参与循环引用的对象：如列表、字典、集合及用户自定义类实例等容器对象。字符串和整数无法持有对其他对象的引用，因此无需跟踪它们。</p>
<p>与 Java 的收集器一样，循环检测器使用分代方法。共有三代，编号为 0、1 和 2。思路与我们之前讨论的分代假说相同：大多数对象死得早，所以经常检查年轻对象，少打扰老对象。默认阈值硬编码在 CPython 的 <a href="https://github.com/python/cpython/blob/v3.9.6/Modules/gcmodule.c#L137">Modules/gcmodule.c</a> 中：</p>
<pre><code>struct gc_generation generations[NUM_GENERATIONS] = {
    /* PyGC_Head,                                    threshold,    count */
    { {(uintptr_t)_GEN_HEAD(0), (uintptr_t)_GEN_HEAD(0)},   700,        0},
    { {(uintptr_t)_GEN_HEAD(1), (uintptr_t)_GEN_HEAD(1)},   10,         0},
    { {(uintptr_t)_GEN_HEAD(2), (uintptr_t)_GEN_HEAD(2)},   10,         0},
};
</code></pre>
<p>你可以验证你的运行时实际使用的是什么：</p>
<pre><code>python3 -c "import gc; print(gc.get_threshold())"
# (700, 10, 10)
</code></pre>
<p>请注意，某些框架和发行版会在启动时通过 gc.set_threshold() 覆盖这些默认值，因此你的环境可能显示不同的值。</p>
<p>第 0 代持有新分配的容器对象。当自上次回收以来的新分配数量超过阈值（默认 700）时，回收第 0 代。幸存的对象被提升到第 1 代。在第 0 代被回收 10 次后，第 1 代被回收一次。幸存者移至第 2 代。在第 1 代被回收 10 次后，第 2 代被回收一次。</p>
<p>效果是第 0 代大约每 700 次分配回收一次，第 1 代大约每 7,000 次，第 2 代大约每 70,000 次。进入第 2 代的长寿对象几乎永远不会被打扰。检测器将其大部分时间花在最年轻的对象上，这些对象最有可能最近变成了垃圾。</p>
<p>你可以看到这些计数：</p>
<pre><code>import gc

# 当前各代阈值
print(gc.get_threshold())  # (700, 10, 10)

# 当前分配计数: (gen0分配, 自上次gen1回收以来的gen0回收数, 自上次gen2回收以来的gen1回收数)
print(gc.get_count())  # 例如 (342, 8, 2)

# 强制进行全量回收
gc.collect()

# 完全禁用循环检测器 (如果你确定代码中没有循环引用)
gc.disable()
</code></pre>
<p>当检测器在某一代码代上运行时，它需要找出哪些对象仅被循环引用保持存活。通过一个例子更容易理解算法。</p>
<p>假设检测器正在查看三个被跟踪的对象：X、Y 和 Z。X 指向 Y 和 Z。Y 指回 X。还有一个局部变量持有对 X 的引用。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-16.png" alt="" /></p>
<p>步骤 1：拷贝引用计数。X=2, Y=1, Z=1。</p>
<p>步骤 2：减去内部引用。Y 指向 X，所以从 X 的副本中减 1 (X 从 2 变为 1)。X 指向 Y，所以从 Y 的副本中减 1 (Y 从 1 变为 0)。X 指向 Z，所以从 Z 的副本中减 1 (Z 从 1 变为 0)。</p>
<p>步骤 3：检查剩余部分。X 的调整后计数为 1。被跟踪集合之外的某些东西（局部变量）仍然指向它。X 存活。Y 和 Z 虽然调整后计数为 0，但它们可以从 X 到达，因此它们也幸存下来。</p>
<p>现在想象局部变量消失了。X 的引用计数掉到 1 (只有 Y 指向它)。运行相同算法：拷贝 X=1, Y=1, Z=1。减去内部引用：X 变为 0, Y 变为 0, Z 变为 0。每个调整后的计数都是零。被跟踪集合之外没有任何东西指向它们。它们仅因彼此而存在。三者都是垃圾。</p>
<p>这就是核心思想。算法寻找那些存在的唯一理由是同一集合中其他对象的目标。</p>
<p>有一个边缘案例困扰了多年：finalizers（终结器）。</p>
<p>终结器是运行时在对象被销毁前调用的方法，给予其清理外部资源（如文件句柄或网络连接）的机会。在 Python 中，这就是 <strong>del</strong> 方法。</p>
<p>假设 A 和 B 处于循环中，且两者都有 <strong>del</strong> 方法。检测器知道它们是垃圾，但要释放它们，它需要打破循环。问题是：哪个 <strong>del</strong> 先运行？如果你先运行 A 的终结器，而它尝试使用 B，但 B 已经正在被销毁，你就会崩溃。如果你先运行 B 的，而它使用 A，同样的问题。没有安全的顺序。</p>
<p>在 Python 3.4 之前，CPython 直接放弃处理这些对象。它将它们放入名为 gc.garbage 的列表中，且永远不释放它们。如果你的代码创建了带有 <strong>del</strong> 的循环引用，你就会有一个静默的内存泄漏。PEP 442 通过在打破任何引用之前调用终结器修复了这个问题。当 A 和 B 的 <strong>del</strong> 运行时，两者都保持完整。只有在所有终结器执行完毕后，检测器才会打破循环并释放对象。</p>
<p>关于 CPython 的内存模型还有一件事值得了解。每当 Python 执行类似 x = some_object 的操作时，它会增加 some_object 的引用计数（C 语言中的 Py_INCREF）。每当变量超出作用域时，它减少计数 (Py_DECREF)。在 C 中这些是普通的整数操作：refcount += 1, refcount -= 1。没有锁，没有原子指令。</p>
<p>在多线程程序中，这是一个问题。两个线程可能同时增加同一个对象的引用计数。如果没有同步，一个增加操作会丢失（经典的竞态条件），之后该对象可能会在有人仍在使用时被释放。</p>
<p>GIL (全局解释器锁) 防止了这种情况。一次只有一个线程执行 Python 字节码，因此两个线程永远不会同时修改同一个引用计数。GIL 免费使所有引用计数操作变得安全，而无需任何原子指令。</p>
<p>这也是移除 GIL 如此困难的原因。如果拿掉它，整个代码库中的每一个 Py_INCREF 和 Py_DECREF 都需要变成原子操作。原子操作比普通整数增量要昂贵得多。Python 3.13 开始附带实验性的 free-threaded 模式，它使用 biased reference counting（偏向引用计数）来降低这种成本：创建对象的线程可以对引用计数进行廉价的非原子更新，只有访问该对象的其他线程才支付原子操作的代价。</p>
<h2>映射回 Wilson：全景图</h2>
<p>每一种现代垃圾回收器都可以映射回 Wilson 在 1992 年描述的两个家族。它们之间的区别在于关于如何最小化停顿、处理并发以及高效管理内存的工程决策。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/garbage-collectors-deep-dive-17.png" alt="" /></p>
<p>从这一对比中可以观察到几点：</p>
<p><strong>Wilson 的追踪式家族在服务器运行时占据主导地位。</strong> 引用计数用于 Swift、Python 和 Rust 的 Arc，但对于具有高分配速率的托管运行时，追踪式收集器是标准做法。循环引用问题无论如何都需要补充追踪步骤，这增加了复杂性，且无法消除每次修改时的引用计数开销。</p>
<p><strong>分代收集除 Go 以外随处可见。</strong> Java 重度利用了分代假说。Python 的循环检测器使用了三代。Go 最初选择不使用分代收集，因为跨代指针写屏障的开销对 Go 的典型工作负载来说不划算。这种情况可能正在改变：最近的 Go 版本中已经开发了实验性的分代支持。</p>
<p><strong>Compaction (整理) vs No compaction 是一个真正的设计分歧点。</strong> Java 收集器进行整理，这允许 bump-pointer 分配（非常快）并消除碎片。Go 不整理，这意味着它永远不需要更新指向已移动对象的指针（更简单的写屏障，无需读屏障以保证正确性）。Go 通过大小类分配器（size-class allocator）来补偿。这是经典的 Wilson 权衡：拷贝和整理收集器以内存开销和指针更新成本换取分配速度和碎片消除。</p>
<p><strong>ZGC 的有色指针是 Wilson 指针标记 (pointer-tagging) 思想的现代实现。</strong> Wilson 提到过在指针中使用位来存储 GC 元数据。ZGC 将此进一步发展，将标记状态、重映射状态和终结状态直接嵌入 64 位指针。在每次指针加载时检查这些位的加载屏障是 ZGC 为亚毫秒级停顿支付的代价。</p>
<p><strong>基本问题从未改变。</strong> 从 roots 开始追踪，标记存活内容，回收其余部分。自 1960 年以来的所有发展都是对 McCarthy 原始洞察的工程改进。</p>
<h2>参考资料</h2>
<ul>
<li><a href="https://dl.acm.org/doi/10.1145/367177.367199">McCarthy, J. (1960). Recursive functions of symbolic expressions and their computation by machine, Part I</a></li>
<li><a href="https://www.cs.rice.edu/~javaplt/311/Readings/wilson92uniprocessor.pdf">Wilson, P. R. (1992). Uniprocessor Garbage Collection Techniques. IWMM ‘92</a></li>
<li><a href="https://tip.golang.org/doc/gc-guide">A Guide to the Go Garbage Collector</a></li>
<li><a href="https://go.dev/blog/ismmkeynote">Getting to Go: The Journey of Go’s Garbage Collector</a></li>
<li><a href="https://github.com/golang/proposal/blob/master/design/17503-eliminate-rescan.md">Proposal: Eliminate STW stack re-scanning &#8211; Austin Clements (2016)</a></li>
<li><a href="https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html">Java Garbage Collection: The G1 Garbage Collector</a></li>
<li><a href="https://openjdk.org/jeps/333">ZGC: The Z Garbage Collector &#8211; JEP 333</a></li>
<li><a href="https://openjdk.org/jeps/439">Generational ZGC &#8211; JEP 439</a></li>
<li><a href="https://peps.python.org/pep-0442/">PEP 442: Safe object finalization</a></li>
</ul>
<hr />
<p><strong>你的“停顿”时刻</strong></p>
<p>GC 的艺术在于平衡。在你的开发生涯中，是否遇到过因为 GC 停顿导致的生产事故？你是倾向于 Go 的极致低延迟，还是 Java G1GC 的高吞吐？<br />
欢迎在评论区分享你的调优经历或吐槽！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p><strong>原「Gopher部落」已重装升级为「Go &amp; AI 精进营」知识星球，快来加入星球，开启你的技术跃迁之旅吧！</strong></p>
<p>我们致力于打造一个高品质的 <strong>Go 语言深度学习</strong> 与 <strong>AI 应用探索</strong> 平台。在这里，你将获得：</p>
<ul>
<li><strong>体系化 Go 核心进阶内容:</strong> 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏，夯实你的 Go 内功。</li>
<li><strong>前沿 Go+AI 实战赋能:</strong> 紧跟时代步伐，学习「Go+AI应用实战」、「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战课」、「OpenClaw实战分享」等，掌握 AI 时代新技能。 </li>
<li><strong>星主 Tony Bai 亲自答疑:</strong> 遇到难题？星主第一时间为你深度解析，扫清学习障碍。</li>
<li><strong>高活跃 Gopher 交流圈:</strong> 与众多优秀 Gopher 分享心得、讨论技术，碰撞思想火花。</li>
<li><strong>独家资源与内容首发:</strong> 技术文章、课程更新、精选资源，第一时间触达。</li>
</ul>
<p>衷心希望「Go &amp; AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚，享受技术精进的快乐！欢迎你的加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-and-ai-tribe-zsxq-small-card.jpg" alt="img{512x368}" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/04/07/garbage-collectors-deep-dive/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>2026 编程语言“饱和度”榜单出炉：JavaScript/Python 已“烂大街”，Go/Rust 成最大赢家？</title>
		<link>https://tonybai.com/2026/04/02/2026-programming-language-saturation-rankings-go-rust-winners/</link>
		<comments>https://tonybai.com/2026/04/02/2026-programming-language-saturation-rankings-go-rust-winners/#comments</comments>
		<pubDate>Thu, 02 Apr 2026 00:08:43 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AIEra]]></category>
		<category><![CDATA[AI时代]]></category>
		<category><![CDATA[Architecturalthinking]]></category>
		<category><![CDATA[Datadriven]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[HorizontalCompetition]]></category>
		<category><![CDATA[Involution]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[ProgrammingLanguages]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Rust]]></category>
		<category><![CDATA[SaturationRankings]]></category>
		<category><![CDATA[Shipping]]></category>
		<category><![CDATA[SupplyDemand]]></category>
		<category><![CDATA[SurvivorBias]]></category>
		<category><![CDATA[SystemArchitect]]></category>
		<category><![CDATA[TechDividend]]></category>
		<category><![CDATA[TechStack]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[UnderlyingPrinciples]]></category>
		<category><![CDATA[VerticalDeepening]]></category>
		<category><![CDATA[交付]]></category>
		<category><![CDATA[供需关系]]></category>
		<category><![CDATA[内卷]]></category>
		<category><![CDATA[幸存者偏差]]></category>
		<category><![CDATA[底层原理]]></category>
		<category><![CDATA[技术栈]]></category>
		<category><![CDATA[技术红利]]></category>
		<category><![CDATA[数据驱动]]></category>
		<category><![CDATA[架构思维]]></category>
		<category><![CDATA[横向竞争]]></category>
		<category><![CDATA[系统架构师]]></category>
		<category><![CDATA[纵向深耕]]></category>
		<category><![CDATA[编程语言]]></category>
		<category><![CDATA[饱和度榜单]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6132</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/04/02/2026-programming-language-saturation-rankings-go-rust-winners 大家好，我是Tony Bai。 在这个技术浪潮汹涌、AI 随时可能掀翻牌桌的时代，每一个程序员心中都悬着一个终极问题： “我现在的技术栈，还能吃几年饭？” 我们每天都在焦虑地刷着各种技术文章，试图从 Google、Anthropic、OpenAI、Nvidia等的风向中，窥探下一个技术红利期。但这些信息往往零散、矛盾，甚至充满了各种培训机构的“幸存者偏差”。 就在半个多月前，X 平台上的一位技术博主 Mojisola Alegbe，基于 Stack Overflow、GitHub Trends、JetBrains 等多方数据，整理并发布了一份极其残酷的私房版《2026 编程语言“饱和度”榜单》。 这篇推文就像一颗深水炸弹，在短短几天内获得了 41.2 万的惊人阅读量。大批开发者涌入评论区，有人哀嚎，有人庆幸，有人愤怒，有人不屑。这张榜单之所以能引爆全网，因为它赤裸裸地揭示了我们这个行业最真实的“供需关系”和“内卷现状”。 今天，我们就来深度扒开这张榜单背后的血泪与真相。看看你我手中的“锤子”，到底还能敲几年钉子。 榜单冲击：你的技术栈，在鄙视链的哪一层？ 让我们先深吸一口气，看看这份令人心跳加速的榜单： JavaScript (66%): 极度饱和 (Extremely Saturated) Python (58%): 非常饱和 (Very Saturated) SQL (49%): 非常饱和 (Very Saturated) TypeScript (35-40%): 高度饱和，且仍在快速增长 Java (26%): 成熟/稳定饱和 C# (18%): 中度饱和 PHP (10-11%): 正在衰退，但仍很普遍 C++ (6-7%): 小众，但用于关键系统 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/2026-programming-language-saturation-rankings-go-rust-winners-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/04/02/2026-programming-language-saturation-rankings-go-rust-winners">本文永久链接</a> &#8211; https://tonybai.com/2026/04/02/2026-programming-language-saturation-rankings-go-rust-winners</p>
<p>大家好，我是Tony Bai。</p>
<p>在这个技术浪潮汹涌、AI 随时可能掀翻牌桌的时代，每一个程序员心中都悬着一个终极问题：</p>
<p><strong>“我现在的技术栈，还能吃几年饭？”</strong></p>
<p>我们每天都在焦虑地刷着各种技术文章，试图从 Google、Anthropic、OpenAI、Nvidia等的风向中，窥探下一个技术红利期。但这些信息往往零散、矛盾，甚至充满了各种培训机构的“幸存者偏差”。</p>
<p>就在半个多月前，X 平台上的一位技术博主 Mojisola Alegbe，基于 Stack Overflow、GitHub Trends、JetBrains 等多方数据，整理并发布了一份极其残酷的私房版《<a href="https://x.com/yehhmisi/status/2031715243622015239">2026 编程语言“饱和度”榜单</a>》。</p>
<p>这篇推文就像一颗深水炸弹，在短短几天内获得了 <strong>41.2 万</strong>的惊人阅读量。大批开发者涌入评论区，有人哀嚎，有人庆幸，有人愤怒，有人不屑。这张榜单之所以能引爆全网，因为它赤裸裸地揭示了我们这个行业最真实的“供需关系”和“内卷现状”。</p>
<p>今天，我们就来深度扒开这张榜单背后的血泪与真相。看看你我手中的“锤子”，到底还能敲几年钉子。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/ai-engineer-gpu-introduction-course-qr.png" alt="" /></p>
<h2>榜单冲击：你的技术栈，在鄙视链的哪一层？</h2>
<p>让我们先深吸一口气，看看这份令人心跳加速的榜单：</p>
<ul>
<li>JavaScript (66%): 极度饱和 (Extremely Saturated)</li>
<li>Python (58%): 非常饱和 (Very Saturated)</li>
<li>SQL (49%): 非常饱和 (Very Saturated)</li>
<li>TypeScript (35-40%): 高度饱和，且仍在快速增长</li>
<li>Java (26%): 成熟/稳定饱和</li>
<li>C# (18%): 中度饱和</li>
<li>PHP (10-11%): 正在衰退，但仍很普遍</li>
<li>C++ (6-7%): 小众，但用于关键系统</li>
<li>Go (4-5%): 低饱和，需求增长中</li>
<li>Kotlin (4-5%): 中度小众 (安卓)</li>
<li>Swift (2%): 小型但专业的生态系统</li>
<li>Rust (2-3%): 低饱和，但正在崛起</li>
</ul>
<p>看完这张图，我猜很多人的第一反应是：</p>
<ul>
<li><strong>前端/Python 工程师</strong>：完了，彻底“烂大街”了，明天就去送外卖。</li>
<li><strong>Java 工程师</strong>：稳如老狗，任你风吹雨打，我自岿然不动。</li>
<li><strong>Go/Rust 工程师</strong>：心中窃喜，果然选对了赛道，未来可期！</li>
<li><strong>PHP 工程师</strong>：……（我 PHP 是最好的语言！）</li>
</ul>
<p>但如果事情真的这么简单，那我们这个行业也未免太无趣了。这张榜单真正有价值的地方，在于它炸出了评论区里无数资深架构师和一线开发者的“人间清醒”。</p>
<h2>社区百态：饱和、内卷与“幸存者偏差”</h2>
<p>在这张榜单的评论区，你可以看到整个技术圈最真实的生态缩影。</p>
<p><strong>阵营一：饱和焦虑派</strong></p>
<p>“完了，我刚想学编程，这可怎么办？”<br />
“怪不得现在工作这么难找……”</p>
<p><strong>阵营二：不屑一顾派</strong></p>
<p>“语言只是工具，解决问题才是关键。”<br />
“这种指标毫无意义。”</p>
<p><strong>阵营三：人间清醒派（重点看这里！）</strong></p>
<p>这部分评论，往往来自那些穿越了数个技术周期的老炮。他们的观点，破具含金量。</p>
<p>一位开发者一针见血地指出：</p>
<blockquote>
<p>“语言的饱和度是个误导性指标。真正的问题不是有多少开发者懂它，而是有多少开发者能用它构建出真正有价值的系统。”</p>
</blockquote>
<p>另一位开发者则更加直接：</p>
<blockquote>
<p>“饱和度百分比毫无意义。重要的是：你能交付吗（Can you ship）？我只看三个信号：1. 真实的生产环境部署（而不是教程）；2. 系统设计的深度（而不只是 CRUD）；3. 在压力下调试复杂问题的能力。JavaScript 饱和度 66%？那又怎样，其中 90% 的人连一个可扩展的架构都设计不出来。”</p>
</blockquote>
<p>而一位博主，更是给出了顶级玩家的“搞钱思路”：</p>
<blockquote>
<p>“聪明的开发者从不追逐‘流行’的语言，他们追逐的是‘高价值’的行业<br />
  &#8211; <strong>Python → AI</strong><br />
  &#8211; <strong>C++ → 高性能系统（游戏、金融）</strong><br />
  &#8211; <strong>Rust → 安全基础设施（区块链、操作系统）</strong><br />
  &#8211; <strong>Go → 云平台（K8s、Docker）</strong><br />
  <strong>追逐金钱，而不是追逐炒作（Follow the money, not the hype）。”</strong></p>
</blockquote>
<h2>架构师的破局之道：从“横向内卷”到“纵向深耕”</h2>
<p>扒开社区的口水战，我们可以总结出三条极其宝贵的“反内卷”生存法则。</p>
<p><strong>第一条：停止在“语言层”的低水平竞争</strong></p>
<p>如果你是一个 Python 开发者，你的核心竞争力绝对不是“比别人多会几个 itertools 的函数”。</p>
<p>评论区里的一条建议非常中肯：</p>
<blockquote>
<p>“不要只学 Python 的语法。<a href="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzIyNzM0MDk0Mg==&amp;action=getalbum&amp;album_id=4446480684395986947#wechat_redirect">去学它底层的 C++ 和 CUDA</a>。这才是 2026 年 AI 热潮中真正值钱的地方。”</p>
</blockquote>
<p>同样的道理，如果你是一个前端开发者，让你在面试中脱颖而出的，绝不是多会几个 CSS 动画技巧，而是你对 V8 引擎的内存管理、对大规模前端项目的架构设计、对 WebAssembly 的底层原理的深刻理解。</p>
<p>饱和的永远是“表层应用”，而“底层原理”的护城河，深不见底。</p>
<p><strong>第二条：将你的技术栈，锚定在高价值的“产业赛道”</strong></p>
<p>你选择的语言，决定了你的“工具”；而你选择的行业，决定了你“工具”的价值。</p>
<p>如果你用 Go，但每天只是在写一些简单的 CRUD 业务，那你和用 PHP 的同行并没有本质区别。</p>
<p>但如果你用 Go，去深耕 <strong>Kubernetes Operator 开发、去搞 Service Mesh、去做 eBPF 的底层监控</strong>，那你将进入一个截然不同的“高价值稀缺区”。</p>
<p>对于大多数开发者来说，最好的策略不是去学一门全新的、不饱和的语言（比如 Zig 或 OCaml），而是在你现有的、最熟悉的语言生态里，找到那个与<strong>“高利润、高壁垒”</strong>行业结合最紧密的纵深方向，然后一头扎进去。</p>
<p><strong>第三条：从“语言专家”进化为“系统架构师”</strong></p>
<p>评论区里，有一个非常有趣的现象：初级开发者在讨论“哪个语言好”，而资深开发者在讨论“如何交付（Ship）”。</p>
<p>当一个系统变得复杂时，瓶颈往往早已不在于某个语言的语法特性，而在于：</p>
<ul>
<li>你如何设计一套可观测的日志与监控体系？</li>
<li>你如何在不同的微服务之间做好 <a href="https://mp.weixin.qq.com/s/MUb3r1juqWIBtzlODbbQ-Q">API 的版本管理与兼容性</a>？</li>
<li>你如何<a href="https://mp.weixin.qq.com/s/evEOYgMe2lZmG2bkpoBe5Q">设计数据库的 Schema</a>，才能在未来两年内扛住 10 倍的流量增长？</li>
</ul>
<p>这些“跨语言”的系统设计能力，才是拉开普通程序员和架构师之间收入差距的根本原因。</p>
<p><strong>语言的红利期是短暂的，而架构的复利是终身的。</strong></p>
<h2>小结：你的价值，由你定义</h2>
<p>这张“饱和度”榜单，与其说是一份“死亡通知单”，不如说是一张“体检报告”。它提醒我们，如果你安于现状，只停留在语言的表层舒适区，那么无论你现在用的是 Go 还是 Python，你都随时可能被更便宜、更年轻的开发者所取代。别忘了还有不断“蚕食”初级甚至中高级程序员工作的AI！</p>
<p>在这个充满不确定性的时代，真正的安全感，来源于：</p>
<ol>
<li><strong>向下扎根</strong>，掌握技术栈的底层原理。</li>
<li><strong>向高处走</strong>，将你的能力锚定在高价值的产业。</li>
<li><strong>向外看</strong>，建立跨越语言鸿沟的系统架构思维。</li>
</ol>
<p>不要再为“哪个语言是宇宙第一”而进行无意义的口水战了。</p>
<p>你的价值，从来不是由你用什么语言决定的，而是由你能用这门语言，解决多大、多复杂、多有价值的问题决定的。</p>
<p>资料链接：https://x.com/yehhmisi/status/2031715243622015239</p>
<hr />
<p><strong>今日互动探讨：</strong></p>
<p>看完这份榜单，你对自己目前的技术栈感到了焦虑，还是庆幸？在你看来，一个语言的“饱和”是危机，还是意味着更成熟的生态和机会？</p>
<p>欢迎在评论区分享你的看法！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/04/02/2026-programming-language-saturation-rankings-go-rust-winners/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>告别古法编程黄金时代：AI 时代不会再有新编程语言诞生的土壤</title>
		<link>https://tonybai.com/2026/03/24/no-soil-for-new-programming-languages-in-ai-era/</link>
		<comments>https://tonybai.com/2026/03/24/no-soil-for-new-programming-languages-in-ai-era/#comments</comments>
		<pubDate>Mon, 23 Mar 2026 23:45:43 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AgenticCoding]]></category>
		<category><![CDATA[AIProgramming]]></category>
		<category><![CDATA[AI编程]]></category>
		<category><![CDATA[AndrejKarpathy]]></category>
		<category><![CDATA[ArtificialIntelligence]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[ClaudeCode]]></category>
		<category><![CDATA[CodeGeneration]]></category>
		<category><![CDATA[CorpusHegemony]]></category>
		<category><![CDATA[Cpp]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[HandcraftedCode]]></category>
		<category><![CDATA[IntermediateRepresentation]]></category>
		<category><![CDATA[LLM]]></category>
		<category><![CDATA[NaturalLanguageProgramming]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ProgrammingLanguages]]></category>
		<category><![CDATA[ProgrammingParadigm]]></category>
		<category><![CDATA[Prompt]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Rust]]></category>
		<category><![CDATA[Software3.0]]></category>
		<category><![CDATA[SoftwareEngineering]]></category>
		<category><![CDATA[SoftwareFactory]]></category>
		<category><![CDATA[spec]]></category>
		<category><![CDATA[TechEvolution]]></category>
		<category><![CDATA[中间码]]></category>
		<category><![CDATA[人工智能]]></category>
		<category><![CDATA[代码生成]]></category>
		<category><![CDATA[古法编程]]></category>
		<category><![CDATA[大模型]]></category>
		<category><![CDATA[技术演进]]></category>
		<category><![CDATA[提示词]]></category>
		<category><![CDATA[智能体编程]]></category>
		<category><![CDATA[编程范式]]></category>
		<category><![CDATA[编程语言]]></category>
		<category><![CDATA[自然语言编程]]></category>
		<category><![CDATA[规格说明书]]></category>
		<category><![CDATA[语料霸权]]></category>
		<category><![CDATA[软件工厂]]></category>
		<category><![CDATA[软件工程]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6092</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/03/24/no-soil-for-new-programming-languages-in-ai-era 大家好，我是Tony Bai。 如果你回望过去十五年的软件工程史，那无疑是编程语言百花齐放的黄金时代。 为了对抗日益膨胀的系统复杂度，人类绞尽脑汁地发明新的“咒语”： Google 推出了 Go 语言，用极简的 Goroutine 拯救了深陷并发地狱的后端工程师； Mozilla 孕育了 Rust，用严苛的所有权机制向内存泄漏和数据竞争宣战； 苹果用 Swift 埋葬了晦涩的 Objective-C； JetBrains 用 Kotlin 为笨重的 Java的使用者提供了一个更优雅的选择； 微软用 TypeScript 彻底规范了狂野的 JavaScript 生态。 每一次新语言的诞生，都伴随着开发者们的狂欢。我们热衷于讨论语法糖、对比编译速度、争论哪种范式更优雅。我们在各大论坛上为自己喜爱的语言摇旗呐喊。 但这已经是最后的余晖了。 站在 2026 年的节点上，当你看着 Claude Code、Cursor 或各类 Coding Agent 在几秒钟内倾泻出数千行逻辑严密的代码时，一个残酷的真相正在浮出水面： 大模型（LLM）的爆发，彻底抽干了孕育下一代通用编程语言的土壤。属于人类的“造语言”游戏，结束了。 这不是危言耸听，而是基于技术演进第一性原理的必然推演。 语料霸权：新语言无法跨越的“生态死局” 在 AI 时代，一门编程语言的生命力不再取决于它的语法有多么优雅，而取决于它在 AI 模型中的“语料权重”。 现存的主流语言（Python, Java, JavaScript, Go, C/C++等）在 GitHub [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/no-soil-for-new-programming-languages-in-ai-era-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/03/24/no-soil-for-new-programming-languages-in-ai-era">本文永久链接</a> &#8211; https://tonybai.com/2026/03/24/no-soil-for-new-programming-languages-in-ai-era</p>
<p>大家好，我是Tony Bai。</p>
<p>如果你回望过去十五年的软件工程史，那无疑是编程语言百花齐放的黄金时代。</p>
<p>为了对抗日益膨胀的系统复杂度，人类绞尽脑汁地发明新的“咒语”：</p>
<p>Google 推出了 Go 语言，用极简的 Goroutine 拯救了深陷并发地狱的后端工程师；</p>
<p>Mozilla 孕育了 Rust，用严苛的所有权机制向内存泄漏和数据竞争宣战；</p>
<p>苹果用 Swift 埋葬了晦涩的 Objective-C；</p>
<p>JetBrains 用 Kotlin 为笨重的 Java的使用者提供了一个更优雅的选择；</p>
<p>微软用 TypeScript 彻底规范了狂野的 JavaScript 生态。</p>
<p>每一次新语言的诞生，都伴随着开发者们的狂欢。我们热衷于讨论语法糖、对比编译速度、争论哪种范式更优雅。我们在各大论坛上为自己喜爱的语言摇旗呐喊。</p>
<p><strong>但这已经是最后的余晖了。</strong></p>
<p>站在 2026 年的节点上，当你看着 <a href="http://gk.link/a/12EPd">Claude Code</a>、Cursor 或各类 Coding Agent 在几秒钟内倾泻出数千行逻辑严密的代码时，一个残酷的真相正在浮出水面：</p>
<p><strong>大模型（LLM）的爆发，彻底抽干了孕育下一代通用编程语言的土壤。属于人类的“造语言”游戏，结束了。</strong></p>
<p>这不是危言耸听，而是基于技术演进第一性原理的必然推演。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/agentic-software-engineering-qr.png" alt="" /></p>
<h2>语料霸权：新语言无法跨越的“生态死局”</h2>
<p>在 AI 时代，一门编程语言的生命力不再取决于它的语法有多么优雅，而取决于它在 AI 模型中的<strong>“语料权重”</strong>。</p>
<p>现存的主流语言（Python, Java, JavaScript, Go, C/C++等）在 GitHub 上积累了数年甚至十余年的海量开源代码。这些代码构成了大模型训练的底座，赋予了 AI 极高的“代码智商”。</p>
<p>当你用 Python 或 Go 提问时，AI 能够瞬间理解你的意图，补全复杂的逻辑，甚至自动发现隐藏的 Bug，因为它的“脑子”里装着上千万个成熟的 Python/Go 示例。</p>
<p><strong>但对于一门新语言来说，这是绝对的死局。</strong></p>
<p>假设明天某个天才发布了一门名为 Nova 的新语言，号称性能超越 C，安全性超越 Rust，语法如 Python 般简洁。</p>
<p>结果会怎样？</p>
<ul>
<li>AI 不会写：因为训练语料里没有 Nova 的代码，大模型对它一无所知，无法提供智能补全。</li>
<li>人类不会用：在“没有 AI 辅助就感觉不会写代码”的今天，一个习惯了口述意图，让AI Coding Agent 自动生成全量代码的程序员，绝不可能去碰一门必须纯手工敲击、AI 无法帮他编写和Debug的语言。</li>
</ul>
<p>这就形成了一个无解的<strong>马太效应</strong>：</p>
<pre><code>没人写就没有语料 -&gt; 没有语料 AI 就不会写 -&gt; AI 不会写人类就不想学 -&gt; 更没人写。
</code></pre>
<p><strong>现存的主流语言通过“语料霸权”，彻底锁死了新语言上升的通道。</strong></p>
<h2>需求降维：为什么我们不再需要“更好写”的语言？</h2>
<p>人类发明新语言的根本动力，是<strong>“人脑的带宽有限”</strong>。</p>
<p>C++ 太容易写出内存泄漏，人脑排查太痛苦，所以我们发明了 Rust，让编译器做“真理警察”。</p>
<p>Java 处理异步回调太繁琐（Callback Hell），所以我们发明了各种新的语法糖。</p>
<p>我们一直在努力打造更锋利、更安全的斧头，因为那是人类自己要挥舞的斧头。</p>
<p>但在 Agentic Coding（智能体编程）时代，挥舞斧头的不再是人，而是不知疲倦的 AI。</p>
<p>当你可以用自然语言对 Agent 说：<em>“用 C++ 实现一个高并发的 HTTP 服务器，并严格检查所有内存泄漏风险，写出 100% 覆盖率的测试用例。”</em></p>
<p>只要 AI 的推理能力足够强，加上自动化的沙箱验证（Eval），它完全可以写出极度安全、高效的 C++ 代码。</p>
<p>如果 AI 能够不知疲倦地处理最繁琐的语法、填补最冗长的样板代码（Boilerplate），并且不出错，那么“语言本身是否易读、是否好写” 似乎就变得不再重要了。</p>
<p>因为代码根本不是给人看的，也不是人写的。当“人脑带宽”不再是瓶颈，发明一种“让人类写得更舒服”的新语言，就失去了最大的现实动机。</p>
<h2>语言的两极化：自然语言与“AI 中间码”</h2>
<p>如果不再有新的面向人类的通用编程语言，未来的代码世界会变成什么样？</p>
<p>答案是：<strong>极端的两极分化。</strong></p>
<p><strong>上层：英语（或自然语言）成为终极编程语言。</strong></p>
<p>Andrej Karpathy 的预言正在成为现实（Software 3.0）。人类不需要学习晦涩的语法，人类只需要学习如何清晰、严谨地表达意图，编写能够精准约束 AI 的 <strong>Spec（规格说明书）</strong>。我们与机器的接口，退回到了人类最擅长的媒介。</p>
<p><strong>底层：只有机器能读懂的“AI 专属语言”。</strong></p>
<p>如果你是大模型厂商（比如 OpenAI 或 Google），当你发现 90% 的代码都是你的模型生成的，你还会让模型生成冗长、为了兼顾人类可读性而充满妥协的 Java 或 Python 代码吗？</p>
<p>不会的。巨头们极有可能会研发一种<strong>专门面向 AI 优化的中间表示语言（Intermediate Representation, IR）</strong>。</p>
<p>这种语言对人类来说如同天书，但对于模型来说：</p>
<ul>
<li>Token 效率极高：原本需要 1000 个 Token 表达的逻辑，这种语言只要 50 个 Token，极大节省推理成本和上下文窗口。</li>
<li>逻辑高度压缩：天生适合并行计算和智能体之间的状态传递。</li>
</ul>
<p>AI 会将人类的自然语言直接“编译”成这种中间码，然后运行。</p>
<p>在这个过程中，介于自然语言和机器码之间、那种专门为了“让人类勉强能懂又能让机器执行”而存在的传统编程语言，其生存空间将被彻底抽空。</p>
<h2>小结：致敬“古法编程”的黄金时代</h2>
<p><img src="https://tonybai.com/wp-content/uploads/2026/no-soil-for-new-programming-languages-in-ai-era-2.png" alt="" /></p>
<p>这听起来有些感伤，但这就是技术演进的无情车轮。</p>
<p>就像今天，依然有人沉迷于机械表的齿轮咬合，依然有人热爱在暗房里冲洗胶卷。</p>
<p><strong>“纯手工编写代码（Handcrafted Code）”</strong>——这种我们曾引以为傲的工业生产方式，未来可能也会退化成一种个人的“艺术爱好”或“思维体操”。我们称之为<strong>“古法编程”</strong>。</p>
<p>在某个安静的周末，你或许依然会打开编辑器，为了兴趣手撸一段优雅的 Go 并发或者 Rust 生命周期，享受那种久违的、直接控制机器的“心流”多巴胺。</p>
<p>但在残酷的商业战场上，古法编程即将落幕。</p>
<p>不要再为语法糖而争论不休，不要再期待下一个能拯救你的新语言。</p>
<p>去锻炼你的系统思维吧，去学着用自然语言精准地描绘你的蓝图。因为在下一个时代，<strong>定义目标的造物主，永远比精通语法的泥瓦匠更稀缺。</strong></p>
<hr />
<p><strong>你还在坚持“古法编程”吗？</strong></p>
<p>面对 AI 现场生成代码的冲击，你是否还会为了某种语言的“优雅语法”而兴奋？在你的理想中，未来的“AI 专用中间码”应该长什么样？你是更享受亲自掌控每一行代码，还是更向往定义目标的“造物主”角色？</p>
<p>欢迎在评论区留下你对“古法编程”时代的最后致敬！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p><strong>原「Gopher部落」已重装升级为「Go &amp; AI 精进营」知识星球，快来加入星球，开启你的技术跃迁之旅吧！</strong></p>
<p>我们致力于打造一个高品质的 <strong>Go 语言深度学习</strong> 与 <strong>AI 应用探索</strong> 平台。在这里，你将获得：</p>
<ul>
<li><strong>体系化 Go 核心进阶内容:</strong> 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏，夯实你的 Go 内功。</li>
<li><strong>前沿 Go+AI 实战赋能:</strong> 紧跟时代步伐，学习「Go+AI应用实战」、「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战课」、「OpenClaw实战分享」等，掌握 AI 时代新技能。 </li>
<li><strong>星主 Tony Bai 亲自答疑:</strong> 遇到难题？星主第一时间为你深度解析，扫清学习障碍。</li>
<li><strong>高活跃 Gopher 交流圈:</strong> 与众多优秀 Gopher 分享心得、讨论技术，碰撞思想火花。</li>
<li><strong>独家资源与内容首发:</strong> 技术文章、课程更新、精选资源，第一时间触达。</li>
</ul>
<p>衷心希望「Go &amp; AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚，享受技术精进的快乐！欢迎你的加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-and-ai-tribe-zsxq-small-card.jpg" alt="img{512x368}" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/03/24/no-soil-for-new-programming-languages-in-ai-era/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>被嘲笑比 Python 还慢？扒开 Go 正则表达式的底层，看看它为了防范“系统猝死”付出了什么</title>
		<link>https://tonybai.com/2026/03/17/why-is-go-regex-so-slow/</link>
		<comments>https://tonybai.com/2026/03/17/why-is-go-regex-so-slow/#comments</comments>
		<pubDate>Mon, 16 Mar 2026 23:28:31 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[benchmark]]></category>
		<category><![CDATA[CatastrophicBacktracking]]></category>
		<category><![CDATA[Codereview]]></category>
		<category><![CDATA[DenialOfService]]></category>
		<category><![CDATA[DFA]]></category>
		<category><![CDATA[DFS]]></category>
		<category><![CDATA[GarbageCollection]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[MemoryManagement]]></category>
		<category><![CDATA[NFA引擎]]></category>
		<category><![CDATA[PCRE]]></category>
		<category><![CDATA[Prefilters]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[RE2]]></category>
		<category><![CDATA[ReDoS]]></category>
		<category><![CDATA[RegularExpressions]]></category>
		<category><![CDATA[RuntimeEfficiency]]></category>
		<category><![CDATA[Rust]]></category>
		<category><![CDATA[SIMD]]></category>
		<category><![CDATA[ThompsonNFA]]></category>
		<category><![CDATA[Zig]]></category>
		<category><![CDATA[代码审查]]></category>
		<category><![CDATA[内存管理]]></category>
		<category><![CDATA[向量化指令]]></category>
		<category><![CDATA[垃圾回收]]></category>
		<category><![CDATA[性能基准测试]]></category>
		<category><![CDATA[拒绝服务攻击]]></category>
		<category><![CDATA[正则表达式]]></category>
		<category><![CDATA[深度优先搜索]]></category>
		<category><![CDATA[灾难性回溯]]></category>
		<category><![CDATA[确定性有限自动机]]></category>
		<category><![CDATA[运行效率]]></category>
		<category><![CDATA[预过滤]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6050</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/03/17/why-is-go-regex-so-slow 大家好，我是Tony Bai。 如果有人问你：在处理纯 CPU 密集型的文本匹配时，Go 和 Python 哪个快？ 相信 99% 的 Go 开发者会毫不犹豫地把票投给 Go。毕竟，一门编译型的静态语言，怎么可能输给拖着 GIL 锁的解释型脚本语言？ 但现实往往比小说更魔幻。 最近，在 Reddit 的 r/golang 论坛上，一张残酷的 Benchmark 跑分图引发了整个 Go 社区的剧烈震荡。一位开发者，使用极其常见的日志解析正则表达式（提取 IP、时间、URI 等），对各大语言进行了一次横评。 结果令人大跌眼镜：同样的数据集，Rust 跑了 3.9 秒，Zig 跑了 1.3 秒，而 Go 居然跑了整整 38.1 秒！整整比第一名 Zig 慢了接近 30 倍！ 如果你再去翻看 Go 官方的 Issue #26623，会看到更绝望的数据：早在2018年的一次正则基准测试中，Go 不仅被 C++ 和 Rust [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/why-is-go-regex-so-slow-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/03/17/why-is-go-regex-so-slow">本文永久链接</a> &#8211; https://tonybai.com/2026/03/17/why-is-go-regex-so-slow</p>
<p>大家好，我是Tony Bai。</p>
<p>如果有人问你：在处理纯 CPU 密集型的文本匹配时，Go 和 Python 哪个快？</p>
<p>相信 99% 的 Go 开发者会毫不犹豫地把票投给 Go。毕竟，一门编译型的静态语言，怎么可能输给拖着 GIL 锁的解释型脚本语言？</p>
<p>但现实往往比小说更魔幻。</p>
<p>最近，在 Reddit 的 r/golang 论坛上，一张残酷的 Benchmark 跑分图<a href="https://www.reddit.com/r/golang/comments/1rr2evh/why_is_gos_regex_so_slow/">引发了整个 Go 社区的剧烈震荡</a>。一位开发者，使用极其常见的日志解析正则表达式（提取 IP、时间、URI 等），对各大语言进行了一次横评。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/why-is-go-regex-so-slow-2.png" alt="" /></p>
<p>结果令人大跌眼镜：同样的数据集，Rust 跑了 3.9 秒，Zig 跑了 1.3 秒，而 Go 居然跑了整整 38.1 秒！整整比第一名 Zig 慢了接近 30 倍！</p>
<p>如果你再去翻看 Go 官方的 <a href="https://github.com/golang/go/issues/26623">Issue #26623</a>，会看到更绝望的数据：早在2018年的一次正则基准测试中，Go 不仅被 C++ 和 Rust 碾压，甚至连 Python 3、PHP 和 Javascript 都能在正则上把 Go 按在地上摩擦。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/why-is-go-regex-so-slow-3.png" alt="" /></p>
<p>一时间，无数 Gopher 信仰崩塌：“为什么 Go 的标准库 regexp 这么慢？”、“连简单的正则都做不好，Go 凭什么做云原生霸主？”</p>
<p>今天，我们就来硬核扒开 Go 语言 regexp 包的底层设计和实现。你会发现，这不是 Go 团队的技术拉跨，而是一场关于“性能、安全与工程哲学”的博弈。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/agentic-software-engineering-qr.png" alt="" /></p>
<h2>原罪：你以为的慢，其实是替 CGO 负重前行</h2>
<p>面对“为什么 Go 的正则比 Python 还慢”的灵魂拷问，Go 核心团队成员 Ian Lance Taylor 给出了第一层解释。</p>
<p>在 Python、PHP 甚至 Node.js 中，你以为你是在运行脚本，其实它们底层都在悄悄“作弊”。这些语言的正则表达式引擎，几乎全部是用高度优化的 C 语言库（主要是 PCRE，Perl Compatible Regular Expressions）编写的。</p>
<p>当你在 Python 里调用 re.match() 时，它瞬间就穿透到了 C 语言的底层，享受着现代 CPU 指令集的极致加速。</p>
<p>那 Go 为什么不用 C？因为 Go 是一门有着“极度洁癖”的语言。</p>
<p>如果 Go 的标准库引入了 C 语言的 PCRE，就必须通过 CGO 来调用。而 CGO 的上下文切换成本极高，更致命的是，它会彻底破坏 Go 引以为傲的“跨平台交叉编译”能力。你再也不能在一个简单的 go build 后，把二进制文件无痛丢到任何 Alpine 容器里了。</p>
<p>因此，Go 团队做出了第一个艰难的决定：完全使用纯 Go 语言，从零手写一个正则表达式引擎。</p>
<p>脱离了 C 语言几十年的底层优化积累，用原生代码去硬刚别人的 C 引擎，这是 Go 看起来“慢”的表层原因。</p>
<p>但这，仅仅是冰山一角。</p>
<h2>路线之争：为了防止系统“猝死”，Go 抛弃了速度</h2>
<p>真正让 Go 正则变得“慢”的，是算法架构上的降维选择。这牵扯到 Go 语言的缔造者之一、大神 Russ Cox (rsc) 的一段往事。</p>
<p>在正则表达式的底层世界里，存在着两大流派：</p>
<ol>
<li><strong>基于回溯（Backtracking）的 NFA 引擎</strong>：代表人物是 PCRE（被 Python、Java、PHP 广泛使用）。</li>
<li><strong>基于 Thompson NFA / DFA 的引擎</strong>：代表人物是 RE2（被 Go、Rust 采用）。</li>
</ol>
<p>PCRE 引擎极快，它支持各种花里胡哨的语法（如前瞻断言 Lookaround、反向引用 Backreferences）。它的算法逻辑是“不撞南墙不回头”的深度优先搜索（DFS）。在匹配正常字符串时，它快如闪电。</p>
<p>但它有一个极其致命的死穴：ReDoS（正则表达式拒绝服务攻击）。</p>
<p>想象一下你写了一个看似无害的正则：</p>
<pre><code>^([a-zA-Z0-9]+\s?)+$
</code></pre>
<p>如果黑客故意传入一个极其恶意的字符串：aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!（注意最后的感叹号）。</p>
<p>PCRE 引擎会陷入可怕的“灾难性回溯”。它会尝试所有可能的组合，时间复杂度瞬间飙升到 <strong>O(2^n)</strong> 级。短短几十个字符的输入，能让单核 CPU 满载运行几年都算不出结果！</p>
<p>2019 年，互联网巨头 Cloudflare 就因为在 WAF 防火墙中写错了一个极其简单的正则表达式，CPU资源瞬间耗尽，导致全球80% 的通过 Cloudflare 代理的网站受到影响，陷入瘫痪长达 27 分钟。这就是 PCRE 回溯引擎的恐怖破坏力。</p>
<p>Russ Cox 在设计 Go 的 regexp 包时，定下了一条铁律：系统安全与可预测性，绝对高于单次请求的极限性能。</p>
<p>因此，Go 彻底抛弃了危险的回溯引擎，选择了基于 <strong>Thompson NFA</strong> 的算法（源自他之前在Google主导设计的 C++ RE2 引擎）。这种算法保证了匹配时间永远是<strong>线性复杂度 O(n)</strong>。</p>
<p>无论黑客传入多么恶意的字符串，Go 的正则引擎绝对不会发生灾难性回溯。它牺牲了在美好情况下的极致快感，换取了在极端恶劣环境下的金身不坏。</p>
<p>这算是 Go 团队最顶级的“克制”吧。</p>
<h2>硬核剖析：Go 的正则，时间到底去哪了？</h2>
<p>既然算法是 O(n) 的，为什么 Go 依然比同样采用 RE2/DFA 思想的 Rust 慢那么多呢？</p>
<p>如果你去追踪 Go 官方的 <a href="https://github.com/golang/go/issues/19629">Issue #19629</a>和<a href="https://github.com/golang/go/issues/11646">Issue #11646</a>，通过 pprof 分析 Go 正则匹配的 CPU 耗时，你会看到几个令人头疼的瓶颈：</p>
<p><strong>1. 沉重的 UTF-8 解析税</strong></p>
<p>Rust 和 C 的很多正则引擎，底层是直接在“字节（Byte）”级别游走的。而 Go 为了贯彻它对 Unicode 的原生支持，regexp 包在内部极其频繁地将输入流解码为 Rune（Go 的 Unicode 字符单位）。这种逐个解析 Rune 的操作，带来了巨大的计算开销。</p>
<p><strong>2. NFA 虚拟线程的内存震荡</strong></p>
<p>在 Go 的底层源码中，你可以看到耗时最高的两个函数是 (<em>machine).add 和 (</em>machine).step。</p>
<p>Go 是通过维护两个“状态队列（稀疏集）”来模拟 NFA 的并行推进的。每读取一个字符，引擎就要把所有可能的状态添加到下一个队列中。这导致了海量的内存重分配（Allocation）和切片拷贝。哪怕是匹配一个简单的长字符串，底层都在疯狂地挪动内存。</p>
<p>既然这么慢，为什么不把 C++ RE2 里那个极速的 DFA（确定性有限状态自动机）移植到 Go 里呢？</p>
<p><a href="https://github.com/golang/go/issues/11646">Issue #11646</a> 记录了这次尝试。开发者 Michael Matloob 曾经试图将 RE2 的 DFA 移植过来，但被 Russ Cox 拦下了。原因很直接：DFA 虽然快，但它在运行时会动态生成大量的状态，如果不加以严格限制，极易引发内存耗尽（OOM）。在 Go 带有 GC 的内存模型下，频繁创建和销毁庞大的 DFA 状态缓存，会让垃圾回收器不堪重负。</p>
<p>于是，Go 的标准库在“安全、内存、性能”的三角博弈中，选择了妥协于现状。</p>
<h2>社区的探索：SIMD 降维打击与 100倍加速的 coregex</h2>
<p>官方的克制固然令人敬佩，但对于身处一线的业务开发者来说，由于正则太慢导致的 CPU 告警，是实实在在的痛点。</p>
<p>“既然官方不愿意改，那我们就自己造轮子！”</p>
<p>在近期的 Issue #26623 中，一位名为 kolkov 的开发者带着他的开源库 coregex 杀入了战场，向 Go 标准库发起了直接的挑战。</p>
<p>coregex 是一个完全用纯 Go 编写的正则库，它的出现直接将 Go 的正则性能拉到了与 Rust 并驾齐驱，甚至在某些场景下超越 Rust 的境地。</p>
<p>它是怎么做到的？它在底层祭出了几个大杀器：</p>
<ol>
<li><strong>SIMD 预过滤（Prefilters）</strong>：它使用了手写的汇编代码（AVX2/SSSE3 指令集），将正则中的静态字符串提取出来，利用 CPU 的向量化指令，一次性对比 32 个字节。像匹配 .*&#46;txt 这种正则，速度直接飙升了 <strong>1500倍</strong>！</li>
<li><strong>带缓存的 Lazy DFA</strong>：它绕过了标准库每次都重算 NFA 的毛病，在运行时动态构建 DFA 缓存，大幅消除了内存分配。</li>
<li><strong>写时复制（COW）的捕获组</strong>：标准库在处理提取子串时会疯狂分配切片。coregex 通过切片状态共享，让内存分配直接减少了 50%。</li>
</ol>
<p>在 kolkov 提供的 CI 跑分中，在 6MB 的输入下，coregex 处理邮箱、URI 的耗时仅为 1.5 毫秒，而标准库耗时高达 260 毫秒。<strong>足足快了 170 倍！</strong></p>
<p>然而，这段极其硬核的改进，依然很难入Go团队法眼，更不用谈在短期内被合并进 Go 的标准库。</p>
<p>一方面，Go 官方目前正在推进自己的内建 SIMD 方案（Issue #73787），不想接入手写的汇编代码；另一方面，社区大牛 Ben Hoyt 在使用 coregex 时发现，如果开启 Longest() 模式（最长匹配模式），这个库的性能会发生严重退化。</p>
<p>这再次印证了标准库开发的残酷：在某几个特定场景下跑到全宇宙第一很容易，但要在一套 API 里无死角地兜底全世界所有的奇葩正则输入，难如登天。</p>
<h2>在 Go 中写正则的正确姿势</h2>
<p>大致了解了底层原理，回到日常开发中，我们该如何应对 Go 正则的性能瓶颈？作为高级 Go 开发者，请务必将以下三条军规刻在脑子里：</p>
<p><strong>第一条：能不用正则，就坚决不用</strong></p>
<p>如果你只是想检查字符串是否包含子串，或者进行简单的前后缀匹配，<strong>永远优先使用 strings.Contains()、strings.HasPrefix() 等内置函数。</strong> 它们底层有优化的实现，在这样简单场景下，速度是 regexp 包不可比拟的。</p>
<p><strong>第二条：将编译前置，远离循环</strong></p>
<p>如果你翻看新手代码，最常见的低级错误就是在 for 循环或者每次 HTTP 请求里调用 regexp.Compile()。</p>
<p>正则的编译过程（生成 NFA 字节码）极其消耗 CPU。请永远在全局变量或 init() 函数中使用 regexp.MustCompile()，将其编译好并复用。Go 的 Regexp 对象是并发安全的，随便多 Goroutine 调用。</p>
<p><strong>第三条：在极端性能要求下，打破“洁癖”</strong></p>
<p>如果你的核心业务（比如高频日志清洗、海量数据 ETL）确实被 regexp 卡住了脖子，不要硬抗。</p>
<p>你可以选择引入通过 CGO 调用 PCRE的Go binding库（比如https://github.com/GRbit/go-pcre），但要注意防范 ReDoS 攻击，或google/re2的Go binding(比如https://github.com/wasilibs/go-re2)，又或是在业务侧尝试社区的野路子 coregex。在生存面前，架构的“洁癖”是可以适当妥协的。</p>
<h2>小结</h2>
<p>“为什么 Go 的正则这么慢？”</p>
<p>这并非一个简单的工程失误。它是一道分水岭，隔开了“追求跑分好看的玩具代码”与“守护千万级并发集群的生产级设计”。</p>
<p>Russ Cox 宁愿忍受整个开源界的群嘲，也没有为了刷榜而去引入危险的回溯引擎。这或许就是 Go 语言能够成为云原生时代头部语言的原因：<strong>不盲目追求上限的巅峰，而是死死守住安全下限。</strong></p>
<h2>参考资料</h2>
<ul>
<li>https://www.reddit.com/r/golang/comments/1rr2evh/why_is_gos_regex_so_slow/</li>
<li>https://github.com/golang/go/issues/26623</li>
<li>https://github.com/golang/go/issues/19629</li>
<li>https://github.com/golang/go/issues/11646</li>
<li>https://swtch.com/~rsc/regexp/</li>
</ul>
<hr />
<p><strong>今日互动探讨：</strong></p>
<p>在你的日常开发中，有没有被由于“写了糟糕的正则表达式”而导致 CPU 飙升 100% 的惨痛经历？你又是如何排查和优化的？</p>
<p>欢迎在评论区分享你的血泪史</p>
<hr />
<p><strong>认知跃迁：读懂底层机制，才能看透系统架构的本质</strong></p>
<p>从放弃 CGO 选择纯 Go 实现，到防范 ReDoS 采用 NFA，再到社区为了榨干 CPU 性能而引入 SIMD。Go 语言的每一个看似“不合理”的设计背后，都隐藏着深邃的系统级考量。</p>
<p>然而，令人遗憾的是，很多开发者写了五六年的 Go 代码，遇到性能瓶颈依然只能靠“瞎猜”和“重启”。他们对 Go 的内存逃逸、Goroutine 调度机制以及标准库的底层数据结构一无所知。</p>
<p>如果你渴望突破“熟练调包侠”的瓶颈，想要像 Russ Cox 这样的顶级大厂架构师一样，看透 Go 语言背后的底层逻辑，建立起自己坚不可摧的技术护城河——</p>
<p>我的极客时间专栏 <strong>《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》</strong> 正是为你量身定制。</p>
<p>在这 30+ 讲极其硬核的内容中，我不仅带你剥开语法糖，深挖 Goroutine 调度、Channel 哲学；更会带你全面吃透 Go 的工程化实践，把底层性能调优背后的逻辑一次性讲透。</p>
<p>目标只有一个：助你完成从“Go 熟练工”到“能做顶级架构决策的 Go 专家”的蜕变！</p>
<p>扫描下方二维码，加入专栏。不要用战术上的勤奋，掩盖战略上的懒惰。让我们一起用架构师的视角，重新认识 Go 语言。</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/go-advanced-course-4.png" alt="" /></p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p><strong>原「Gopher部落」已重装升级为「Go &amp; AI 精进营」知识星球，快来加入星球，开启你的技术跃迁之旅吧！</strong></p>
<p>我们致力于打造一个高品质的 <strong>Go 语言深度学习</strong> 与 <strong>AI 应用探索</strong> 平台。在这里，你将获得：</p>
<ul>
<li><strong>体系化 Go 核心进阶内容:</strong> 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏，夯实你的 Go 内功。</li>
<li><strong>前沿 Go+AI 实战赋能:</strong> 紧跟时代步伐，学习「Go+AI应用实战」、「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战课」、「OpenClaw实战分享」等，掌握 AI 时代新技能。 </li>
<li><strong>星主 Tony Bai 亲自答疑:</strong> 遇到难题？星主第一时间为你深度解析，扫清学习障碍。</li>
<li><strong>高活跃 Gopher 交流圈:</strong> 与众多优秀 Gopher 分享心得、讨论技术，碰撞思想火花。</li>
<li><strong>独家资源与内容首发:</strong> 技术文章、课程更新、精选资源，第一时间触达。</li>
</ul>
<p>衷心希望「Go &amp; AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚，享受技术精进的快乐！欢迎你的加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-and-ai-tribe-zsxq-small-card.jpg" alt="img{512x368}" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/03/17/why-is-go-regex-so-slow/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>硬核测评：哪门语言最受 AI 宠爱？13 种语言横向对比，Go 表现如何？</title>
		<link>https://tonybai.com/2026/03/09/hardcore-review-13-languages-ai-favorite-go-performance/</link>
		<comments>https://tonybai.com/2026/03/09/hardcore-review-13-languages-ai-favorite-go-performance/#comments</comments>
		<pubDate>Mon, 09 Mar 2026 00:02:44 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AIAgent]]></category>
		<category><![CDATA[AIProgramming]]></category>
		<category><![CDATA[AI智能体]]></category>
		<category><![CDATA[AI编程]]></category>
		<category><![CDATA[benchmark]]></category>
		<category><![CDATA[BorrowChecker]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[ClaudeCode]]></category>
		<category><![CDATA[CodeGeneration]]></category>
		<category><![CDATA[CompilationSpeed]]></category>
		<category><![CDATA[DeveloperExperience]]></category>
		<category><![CDATA[DynamicLanguages]]></category>
		<category><![CDATA[FunctionalLanguages]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[Haskell]]></category>
		<category><![CDATA[InferenceCost]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[mini-git]]></category>
		<category><![CDATA[Ocaml]]></category>
		<category><![CDATA[PerformanceReview]]></category>
		<category><![CDATA[ProgrammingLanguages]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Rust]]></category>
		<category><![CDATA[StaticLanguages]]></category>
		<category><![CDATA[TypeChecking]]></category>
		<category><![CDATA[代码生成]]></category>
		<category><![CDATA[借用检查器]]></category>
		<category><![CDATA[函数式语言]]></category>
		<category><![CDATA[动态语言]]></category>
		<category><![CDATA[基准测试]]></category>
		<category><![CDATA[开发者体验]]></category>
		<category><![CDATA[性能测评]]></category>
		<category><![CDATA[推理成本]]></category>
		<category><![CDATA[类型检查]]></category>
		<category><![CDATA[编程语言]]></category>
		<category><![CDATA[编译速度]]></category>
		<category><![CDATA[静态语言]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6010</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/03/09/hardcore-review-13-languages-ai-favorite-go-performance 大家好，我是Tony Bai。 随着 Claude Code、Gemini Cli、Codex 等 AI 编程工具的全面普及，“让 AI 写代码”已经从极客的玩具变成了日常的生产力。随之而来的是一个触及灵魂的问题：哪种编程语言最适合交给 AI 去写？ 作为 Gopher，我们一直为 Go 语言的“极简语法”、“极速编译”和“强类型安全”感到自豪。我们理所当然地认为，这种没有任何隐式魔法、像白开水一样的语言，绝对是 LLM 的最爱。 然而，现实总是比直觉更骨感。近日，Ruby 核心提交者 Yusuke Endoh（@mame）发布了一份名为 ai-coding-lang-bench 的硬核定量测评报告。他使用 Claude Code（Opus 4.6 模型）对 13 种主流编程语言进行了系统性横向对比。 在这场涵盖了动态语言、静态语言和函数式语言的混战中，Go 语言的表现究竟如何？ 是力压群雄，还是黯然失色？那些备受人类推崇的静态类型系统，在 AI 面前是否成了累赘？ 本文和大家一起阅读和拆解这份报告，为你揭晓 AI 时代的语言偏好图谱。 实验设计：让 AI 写一个 Mini-Git 在评价这份报告之前，我们先来看看它的实验设计，这是目前业内少见的、针对 AI Agent 的工程化能力的量化评估。 任务目标：让 Claude Code (Opus 4.6) [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/hardcore-review-13-languages-ai-favorite-go-performance-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/03/09/hardcore-review-13-languages-ai-favorite-go-performance">本文永久链接</a> &#8211; https://tonybai.com/2026/03/09/hardcore-review-13-languages-ai-favorite-go-performance</p>
<p>大家好，我是Tony Bai。</p>
<p>随着 <a href="http://gk.link/a/12EPd">Claude Code</a>、<a href="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzIyNzM0MDk0Mg==&amp;action=getalbum&amp;album_id=4067128336651386882#wechat_redirect">Gemini Cli</a>、Codex 等 AI 编程工具的全面普及，“让 AI 写代码”已经从极客的玩具变成了日常的生产力。随之而来的是一个触及灵魂的问题：<strong>哪种编程语言最适合交给 AI 去写？</strong></p>
<p>作为 Gopher，我们一直为 Go 语言的“极简语法”、“极速编译”和“强类型安全”感到自豪。我们理所当然地认为，这种没有任何隐式魔法、像白开水一样的语言，绝对是 LLM 的最爱。</p>
<p>然而，现实总是比直觉更骨感。近日，Ruby 核心提交者 Yusuke Endoh（@mame）发布了<a href="https://github.com/mame/ai-coding-lang-bench">一份名为 ai-coding-lang-bench 的硬核定量测评报告</a>。他使用 Claude Code（Opus 4.6 模型）对 13 种主流编程语言进行了系统性横向对比。</p>
<p>在这场涵盖了动态语言、静态语言和函数式语言的混战中，<strong>Go 语言的表现究竟如何？</strong> 是力压群雄，还是黯然失色？那些备受人类推崇的静态类型系统，在 AI 面前是否成了累赘？</p>
<p>本文和大家一起阅读和拆解这份报告，为你揭晓 AI 时代的语言偏好图谱。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/agentic-software-engineering-qr.png" alt="" /></p>
<h2>实验设计：让 AI 写一个 Mini-Git</h2>
<p>在评价这份报告之前，我们先来看看它的实验设计，这是目前业内少见的、针对 AI Agent 的工程化能力的量化评估。</p>
<p><strong>任务目标</strong>：让 Claude Code (Opus 4.6) 从零开始实现一个 mini-git（简化版的 Git）。这是一个极具代表性的任务，它包含了文件 I/O、哈希计算、数据结构操作以及命令行接口，足以考验模型对语言生态的综合运用能力。</p>
<p>测试被巧妙地分为两个阶段，模拟了真实的软件生命周期：</p>
<ul>
<li>v1 (新项目构建)：实现基础的 init, add, commit 和 log。</li>
<li>v2 (特性扩展)：在 v1 的基础上，增加 status, diff, checkout, reset, rm, show 等复杂指令。</li>
</ul>
<p><strong>提示词（Prompt）极其极简</strong>：“阅读 SPEC-v1.txt，实现它，并确保 test-v1.sh 测试通过。”这种设计最大程度地减少了人类指令的干预，纯粹考验 AI 代理在闭环环境下的自主编码、调试和测试能力。</p>
<p><strong>参赛选手（13种语言/15种配置）</strong>：</p>
<ul>
<li>动态语言：Python, Ruby, JavaScript, Perl, Lua</li>
<li>动态+类型检查器：Python/mypy, Ruby/Steep</li>
<li>静态语言：TypeScript, Go, Rust, C, Java</li>
<li>函数式语言：Scheme (动态), OCaml (静态), Haskell (静态)</li>
</ul>
<p>每种语言配置运行 <strong>20 次</strong>，以消除 LLM 生成的随机性带来的误差，并统计其耗时（Time）、成本（Cost，即 Token 消耗）和代码行数（LOC）。</p>
<h2>核心发现：动态语言逆袭，Go 位居第二梯队</h2>
<p>如果仅看总耗时和总成本（v1 + v2），测试结果呈现出了令人瞩目的阶梯式分布。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/hardcore-review-13-languages-ai-favorite-go-performance-2.png" alt="" /></p>
<h3>第一梯队：Ruby, Python, JavaScript 的绝对统治</h3>
<p>在这场 AI 编程竞速中，Ruby（73.1s）、Python（74.6s）和 JavaScript（81.1s）组成了无可争议的第一阵营。</p>
<p>它们不仅生成速度最快、消耗 API 成本最低（均在 $0.40 以下），而且在 20 次测试中表现出了极高的稳定性（标准差极小）。</p>
<p>对于 AI 来说，生成这三种语言的代码就像呼吸一样自然。它们无需繁琐的项目初始化配置（如 Cargo.toml 或 package.json），可以做到“建个文件直接跑”，这种极简的工作流在 v1 阶段（新项目构建）优势极大。</p>
<h3>第二梯队：被“强类型”拖慢脚步的 Go 与 Java</h3>
<p>现在，来回答大家最关心的问题：Go 表现如何？</p>
<p>答案是：位居第二梯队。Go 的总耗时为 101.6s，平均成本 $0.50。中规中矩。Go 虽然在语法上非常克制，但依然落后于 Python 和 JS 等动态语言。与之类似，Java（115.4s）也因为繁琐的语法结构和强类型约束，留在了这一梯队。</p>
<p>尽管如此，Go 在整个 20 次测试中没有出现一次失败（0 次 fail），这证明了 <a href="https://tonybai.com/2026/01/04/stop-lying-to-the-compiler">Go 的编译器在防止 AI 产生“幻觉 Bug”方面，发挥了极其可靠的安全网作用</a>。</p>
<h3>“后进生”阵营：Rust 与 C 的挣扎</h3>
<p>备受人类极客推崇的 Rust（113.7s，且有 2 次失败）和底层的 C（155.8s）在测试中显得步履维艰。</p>
<p>尤为值得注意的是，在总共 600 次的独立运行中，只有 Rust (2次) 和 Haskell (1次) 出现了测试失败（未能最终跑通 Shell 脚本）的情况。这两门语言都以其极高的心智负担和“编译器教你做人”的严格程度而闻名。</p>
<p>这也是将Rust列入“后进生”阵营的主要原因。如果用《飞驰人生》的拉力赛来比喻，Rust 相当于在40站的赛季中，有两站没能完赛！</p>
<h2>深度剖析：为什么 AI 更偏爱动态语言？</h2>
<p>在传统的工程视角中，“静态类型防止低级 Bug”、“动态语言难以维护”是金科玉律。但在 LLM 驱动的 Agent 开发流中，这个逻辑为何失效了？作者 Yusuke Endoh 提出了几个关键的解释维度。</p>
<h3>训练数据的“虹吸效应”</h3>
<p>LLM 的能力直接取决于训练语料的规模和质量。Python、JavaScript 和 Ruby 是过去十几年 Web 开发的绝对主流。GitHub 上海量的这三种语言的开源代码、StackOverflow 上的问答，为 Claude Code 提供了极其丰富的“预训练肌肉记忆”。</p>
<p>当 AI 需要实现一个功能时，它在 Python 的隐空间（Latent Space）中寻找最优解的路径，远比在 Haskell 甚至 Rust 中要清晰、笔直得多。</p>
<h3>静态类型的“双刃剑”与重构阻力</h3>
<p>静态类型系统的初衷是约束人类，防止我们在重构时犯错。但在 AI 的“ Prompt -> 生成 -> 测试报错 -> 思考 -> 再生成”的迭代循环中，严格的类型检查反而成了巨大的“摩擦力”。</p>
<ul>
<li>编译成本与调试死锁：在 Rust 或 C 中，当 AI 生成的代码出现类型不匹配时，它需要花费大量的 Token 去阅读复杂的编译器报错信息。有时，为了解决一个简单的借用检查器（Borrow Checker）报错，AI 可能会陷入漫长的、无休止的“试错-编译失败”死循环。</li>
<li>重构牵一发而动全身：在 v2 特性扩展阶段，往往需要修改现有的数据结构。对于 Python，AI 只需要在字典里加个 key；而对于 Rust 或 Java，这可能意味着需要重构一系列的 Struct、更新类型签名、甚至修改与之相关的无数个函数的参数声明。这种“爆炸半径”极大地增加了耗时。</li>
</ul>
<h3>“附加类型检查”的巨大损耗</h3>
<p>报告中一个非常有意思的对照组是：原生动态语言 vs 附加类型检查器的动态语言。</p>
<ul>
<li>Python (74.6s) vs Python/mypy (125.3s) —— 变慢了 1.6~1.7 倍。</li>
<li>Ruby (73.1s) vs Ruby/Steep (186.6s) —— 变慢了 2.0~3.2 倍！</li>
</ul>
<p>这证明了，迫使 AI 在动态语言中编写严谨的类型注解（Type Annotations），是一项极其昂贵的任务。模型需要耗费额外的算力去推导类型、生成类型声明文件，并且在类型检查器报错时，还要去修复那些在纯动态模式下可能根本不影响运行的“伪 Bug”。</p>
<h3>代码量（LOC）的迷思：越短越好吗？</h3>
<p>我们通常认为，写得越少，跑得越快。但数据打破了这个迷思。</p>
<p>Haskell 和 OCaml 生成的最终代码行数（224行和 216行）是所有语言中最少的，甚至少于 Python 和 Ruby。然而，它们在生成时间上的表现却排在倒数（Haskell 耗时最长，达 174s）。</p>
<p>这表明，对于 AI 来说，函数式语言那种高度抽象、信息密度极大的代码，生成和推理的成本远高于像 Python、Go 那种稍微啰嗦但逻辑平铺直叙的“大白话”代码。浓缩的未必是精华，对于 LLM 来说，高度浓缩往往意味着更高的生成熵和更高的试错概率。</p>
<h2>行业启示：我们需要重新思考 AI 时代的技术栈选型</h2>
<p>面对这份详实的基准测试报告，无论你是 CTO 还是普通开发者，都必须开始重新审视未来的技术选型逻辑。</p>
<h3>动态语言是快速原型的“绝对王者”</h3>
<p>如果你正在启动一个新项目，或者需要用 AI Agent 快速验证一个业务流程，Python 和 TypeScript 是首选（报告中 JavaScript 表现优于 TS，但在实际工程中 TS 的综合权衡更佳）。</p>
<p>不要迷信“大型项目必须一开始就上强类型编译语言”。在需求快速变化的初期，让 AI 用动态语言狂飙突进，是获取业务反馈最高效的手段。</p>
<h3>性能王者们的困境：Go 与 Rust 在 AI 时代掉队了吗？</h3>
<p>看到测评数据，很多 Gopher 可能会感到失落：难道注重工程严谨性和系统级性能的静态语言，真的在 AI 时代掉队了吗？</p>
<p>结论并非如此悲观。我们需要明确一点：Agent 测评的速度，不等于软件最终运行的速度。</p>
<ul>
<li>业务试错 vs 基础设施：AI Agent 目前最擅长、也最快速能完成的，是写“胶水逻辑”和“业务 CRUD”。在这些领域，Python 确实快。但当你的系统涉及到高并发、内存精细控制、或者需要打包为轻量级容器部署时，人类依然需要 Go。</li>
<li>容错的底线：在这场 600 次的庞大测试中，只有 Rust 和 Haskell 出现了最终测试失败，而 Go 保持了完美的 100% 成功率。这恰恰说明，Go 在“极度灵活（易幻觉）”与“极度严格（难生成）”之间，找到了一个非常微妙的平衡点。它可能不是 AI 写得最快的，但它一定是 AI 写出来最让人放心的系统级语言。</li>
</ul>
<p>我们不应期待 AI Agent 能够像写 Python 脚本一样，如德芙般丝滑地生成出一个复杂的 Go 并发系统。但在 AI 给出的初稿之上，Go 语言极佳的可读性和统一的规范，将为人类工程师的最终审查（Code Review）节省巨大的精力。</p>
<h2>小结：下一个十年的编程语言，长什么样？</h2>
<p>ai-coding-lang-bench 给我们上了生动的一课。它揭示了当前 LLM 的偏好：<strong>它们喜欢有海量训练数据的、灵活的、不需要应对死板编译器的语言。</strong></p>
<p>但我们必须认识到，这只是一份基于 2026 年初模型（Claude Opus 4.6）的快照。未来的 AI 编程语言形态，可能会朝着两个方向演进：</p>
<ol>
<li>AI Native 语言的诞生：抛弃目前设计给人类阅读的语法，出现一种专门为了降低 LLM 生成 Token 成本、且天然抗幻觉的机器中间语言。</li>
<li>现有静态语言的“Agent 友好化”编译模式：Go 和 Rust 可能会进化出一种特殊的编译模式。在这个模式下，编译器不仅是冷冰冰地报错，还能以结构化的、对 LLM 更友好的方式提供“修复建议”，从而大幅缩短 Agent 修复编译错误的反馈回路。</li>
</ol>
<p>无论如何，浪潮已经来临。在 AI 主导代码生成的新时代，我们评价一门编程语言的标准，正在从“它对人类大脑是否友好”，悄然转变为<strong>“它对大模型推理是否友好”</strong>。</p>
<p>而在这场新赛道上，动态语言们，已经抢跑了。</p>
<p>本文核心数据与图表均来源于 GitHub 项目 <a href="https://github.com/mame/ai-coding-lang-bench">mame/ai-coding-lang-bench</a>。</p>
<hr />
<p><strong>你的 AI 编程初体验</strong></p>
<p>看完这个排名，你是感到意外，还是早已感同身受？在你日常使用 AI 编程时，你觉得它写哪种语言最让你省心？你是否也曾为了修一个 AI 写的编译错误而陷入“死循环”？</p>
<p>欢迎在评论区分享你的“AI 协作”红黑榜！</p>
<hr />
<p>“语言的严格性正在变成 AI 的摩擦力？在 AI 时代，掌握一套能驱动 Agent 自动化、自修复的‘工作流’比死磕语法更重要。我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将教你如何利用 Claude Code 结合 Spec 驱动开发，构建真正高产出的‘软件工厂’。”</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p><strong>原「Gopher部落」已重装升级为「Go &amp; AI 精进营」知识星球，快来加入星球，开启你的技术跃迁之旅吧！</strong></p>
<p>我们致力于打造一个高品质的 <strong>Go 语言深度学习</strong> 与 <strong>AI 应用探索</strong> 平台。在这里，你将获得：</p>
<ul>
<li><strong>体系化 Go 核心进阶内容:</strong> 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏，夯实你的 Go 内功。</li>
<li><strong>前沿 Go+AI 实战赋能:</strong> 紧跟时代步伐，学习「Go+AI应用实战」、「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战课」、「OpenClaw实战分享」等，掌握 AI 时代新技能。 </li>
<li><strong>星主 Tony Bai 亲自答疑:</strong> 遇到难题？星主第一时间为你深度解析，扫清学习障碍。</li>
<li><strong>高活跃 Gopher 交流圈:</strong> 与众多优秀 Gopher 分享心得、讨论技术，碰撞思想火花。</li>
<li><strong>独家资源与内容首发:</strong> 技术文章、课程更新、精选资源，第一时间触达。</li>
</ul>
<p>衷心希望「Go &amp; AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚，享受技术精进的快乐！欢迎你的加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-and-ai-tribe-zsxq-small-card.jpg" alt="img{512x368}" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/03/09/hardcore-review-13-languages-ai-favorite-go-performance/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AI 时代的新王座：为什么说 Go 可能是开发 AI Agent 的最佳语言？</title>
		<link>https://tonybai.com/2026/03/07/why-go-is-the-best-language-for-ai-agents/</link>
		<comments>https://tonybai.com/2026/03/07/why-go-is-the-best-language-for-ai-agents/#comments</comments>
		<pubDate>Fri, 06 Mar 2026 23:51:18 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AIAgent]]></category>
		<category><![CDATA[AIHallucinations]]></category>
		<category><![CDATA[AI幻觉]]></category>
		<category><![CDATA[AI智能体]]></category>
		<category><![CDATA[CodeGeneration]]></category>
		<category><![CDATA[CodeReadability]]></category>
		<category><![CDATA[CodeReviewer]]></category>
		<category><![CDATA[CognitiveLoad]]></category>
		<category><![CDATA[CompilationSpeed]]></category>
		<category><![CDATA[ConcurrencyNeeds]]></category>
		<category><![CDATA[Containerization]]></category>
		<category><![CDATA[DeveloperExperience]]></category>
		<category><![CDATA[EmotionalValue]]></category>
		<category><![CDATA[GarbageCollection]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[infrastructure]]></category>
		<category><![CDATA[Microservices]]></category>
		<category><![CDATA[Pragmatism]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Rust]]></category>
		<category><![CDATA[SoftwareEngineering]]></category>
		<category><![CDATA[StaticCompilation]]></category>
		<category><![CDATA[StaticLinking]]></category>
		<category><![CDATA[SyntaxMinimalism]]></category>
		<category><![CDATA[UnifiedCodeStyle]]></category>
		<category><![CDATA[VibeCoding]]></category>
		<category><![CDATA[代码可读性]]></category>
		<category><![CDATA[代码审查者]]></category>
		<category><![CDATA[代码生成]]></category>
		<category><![CDATA[垃圾回收]]></category>
		<category><![CDATA[基础设施]]></category>
		<category><![CDATA[实用主义]]></category>
		<category><![CDATA[容器化]]></category>
		<category><![CDATA[并发需求]]></category>
		<category><![CDATA[开发者体验]]></category>
		<category><![CDATA[微服务]]></category>
		<category><![CDATA[情绪价值]]></category>
		<category><![CDATA[氛围编程]]></category>
		<category><![CDATA[统一代码风格]]></category>
		<category><![CDATA[编译速度]]></category>
		<category><![CDATA[认知负荷]]></category>
		<category><![CDATA[语法极简主义]]></category>
		<category><![CDATA[软件工程]]></category>
		<category><![CDATA[静态编译]]></category>
		<category><![CDATA[静态链接]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=5995</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/03/07/why-go-is-the-best-language-for-ai-agents 大家好，我是Tony Bai。 当我们在谈论 AI 编程时，Python 似乎是那个无需讨论的“默认选项”。 然而，随着 AI 应用从模型训练（Training）走向自主智能体（Agents）和复杂的工程落地，基础设施层的语言选型正在悄然发生变化。近日，开源数据编排工具 Bruin 的作者发表了一篇题为《Go 是开发 AI Agents 的最佳语言》的文章，在 Hacker News 上引发了数百条跨语言阵营的激烈辩论。 为什么一位有着 10 年 Python 和 JS 经验的开发者，最终选择用 Go 来构建现代 AI 基础设施？在 AI 生成代码（AI-Generated Code）日益普及的今天，编程语言的“静态类型”、“编译速度”和“语法极简主义”又被赋予了怎样的新维度价值？ 本文将深度拆解这场争论，带你探讨在“Vibe Coding（氛围编程）”时代，Go 语言如何凭借其独特的设计哲学，意外地命中 AI Agent 开发的甜点。 为什么是 Go？来自生产一线的工程反思 Bruin 是一个开源的 ETL（提取、转换、加载）工具。在数据工程领域，Python 拥有统治级的地位（Pandas, Airflow 等），按理说，Bruin 完全应该用 Python 编写。 但作者最终选择了 Go。原因在于，AI Agent [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/why-go-is-the-best-language-for-ai-agents-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/03/07/why-go-is-the-best-language-for-ai-agents">本文永久链接</a> &#8211; https://tonybai.com/2026/03/07/why-go-is-the-best-language-for-ai-agents</p>
<p>大家好，我是Tony Bai。</p>
<p>当我们在谈论 AI 编程时，Python 似乎是那个无需讨论的“默认选项”。</p>
<p>然而，随着 AI 应用从模型训练（Training）走向自主智能体（Agents）和复杂的工程落地，基础设施层的语言选型正在悄然发生变化。近日，开源数据编排工具 Bruin 的作者发表了一篇题为《<a href="https://getbruin.com/blog/go-is-the-best-language-for-agents/">Go 是开发 AI Agents 的最佳语言</a>》的文章，在 Hacker News 上引发了数百条跨语言阵营的<a href="https://news.ycombinator.com/item?id=47222270">激烈辩论</a>。</p>
<p>为什么一位有着 10 年 Python 和 JS 经验的开发者，最终选择<a href="https://tonybai.com/2026/02/18/why-we-chose-go-over-python-for-llm-gateways">用 Go 来构建现代 AI 基础设施</a>？在 AI 生成代码（AI-Generated Code）日益普及的今天，编程语言的“静态类型”、“编译速度”和“语法极简主义”又被赋予了怎样的新维度价值？</p>
<p>本文将深度拆解这场争论，带你探讨在“Vibe Coding（氛围编程）”时代，Go 语言如何凭借其独特的设计哲学，意外地命中 AI Agent 开发的甜点。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/agentic-software-engineering-qr.png" alt="" /></p>
<h2>为什么是 Go？来自生产一线的工程反思</h2>
<p>Bruin 是一个开源的 ETL（提取、转换、加载）工具。在数据工程领域，Python 拥有统治级的地位（Pandas, Airflow 等），按理说，Bruin 完全应该用 Python 编写。</p>
<p>但作者最终选择了 Go。原因在于，AI Agent 和数据编排工具在本质上属于基础设施（Infrastructure），它们面临的工程约束与模型训练截然不同：</p>
<ol>
<li>极致的并发需求：Agent 绝大部分时间都在等待外部 API 的响应（OpenAI, Anthropic）。Go 极其轻量的 Goroutine 机制（2KB 栈空间，极低的上下文切换成本）允许在单机上轻松维持数万个并发请求，而 Python 的 GIL（全局解释器锁）即使配合 asyncio，在 500-1000 RPS 后也会遇到明显的线程竞争瓶颈。(注：最新版Python已经去除了GIL的限制。)</li>
<li>极简的部署体验：Go 编译出的单一静态二进制文件，无需像 Python 那样处理复杂的虚拟环境（venv）、依赖冲突和运行版本问题。对于需要在用户机器上运行的 CLI 工具来说，Go 是“分发即运行”的典范。</li>
<li>跨平台验证的便利：Go 一等公民的跨平台编译能力，意味着不仅开发者可以轻松构建多平台产物，未来的“后台 AI Agent”也能在一个隔离的沙箱中快速验证代码的跨平台兼容性。</li>
</ol>
<p>除了上述硬核的工程指标外，作者还坦诚地分享了一个极其主观，但对初创团队至关重要的考量：开发体验（Developer Experience）与情绪价值。</p>
<p>作者将在很长一段时间内作为项目的核心贡献者，他深刻地意识到：</p>
<blockquote>
<p>“对于一个小型团队来说，在构建大型项目时，快乐和活力（Joy and Energy）是最稀缺的资源之一。因此，至关重要的是，我不能对自己每天要面对的技术栈感到畏惧或厌烦。”</p>
</blockquote>
<p>Go 语言或许在某些特性上不如 Python 灵活，也不如 Rust 表达力强，但它带来的那种“一切尽在掌握”的确定性和快速获得反馈的成就感，能让开发者在漫长的马拉松式开发中保持心流状态。这种心理层面的正向反馈，在 AI Agent 这种充满不确定性的前沿领域探索中，往往是支撑团队走过低谷、坚持到黎明的关键力量。</p>
<p>如果说以上只是 Go 作为“云原生王者”的常规操作，那么在引入大语言模型（LLM）作为“代码生成器”后，Go 的语言特性产生了奇妙的化学反应。</p>
<h2>静态编译：给 AI 戴上“紧箍咒”</h2>
<p>当 Coding Agent 开始每分钟吐出成千上万行代码时，最大的挑战不再是“如何生成”，而是“如何证明它有效”。</p>
<p>在解释型语言（如 Python 或 JavaScript）中，代码的正确性往往只有在运行到特定分支时才能被验证。作者指出，这是 Go 在对抗 AI 幻觉时最大的优势之一：Go 是一门强类型的编译型语言。</p>
<h3>编译器的“守门员”效应</h3>
<p>当你用 LLM 生成 Go 代码时，go build 成了一道天然且严苛的防火墙。类型不匹配、未使用的变量、错误的函数签名——这些占据了 AI 幻觉相当大比例的低级错误，会被 Go 编译器瞬间无情地驳回。</p>
<p>正如一位 HN 网友 所言：</p>
<blockquote>
<p>“在这个人人都在‘氛围编程（vibing left and right）’的时代，你迫切需要一个编译器在背后支持你。Go 让你可以写稍微随意一点的代码，但又不会像 Python 或 JS 那样毫无底线。编译器扮演了看门人的角色，将混乱控制在一定范围内。”</p>
</blockquote>
<h3>为什么不是 Rust？</h3>
<p>讲到编译期安全，Rust 绝对是无可争议的王者。但为什么作者认为 Go 比 Rust 更适合 AI Agent？</p>
<ul>
<li>迭代速度决定一切：AI Agent 的工作流是一个“生成 -> 编译 -> 报错 -> 修复”的紧密反馈循环（Feedback Loop）。Go 的编译速度几乎是瞬时的，这使得 LLM 的试错循环可以极快地运转。而 Rust 漫长的编译时间，在这里成为了致命的瓶颈。</li>
<li>借用检查器的“认知负荷”：Rust 的内存模型（生命周期、借用）极其复杂。现阶段的 LLM 在处理复杂的借用关系时，常常会陷入“为了让编译器闭嘴而无脑 clone()”的陷阱，导致生成的代码偏离 Rust 的最佳实践。</li>
<li>更平缓的试错成本：Go 的垃圾回收（GC）机制让 AI（以及审查代码的人类）可以专注于业务逻辑，而不必在内存管理上耗费计算 token 和审查精力。</li>
</ul>
<p>简单来说：Rust 的上限极高，但门槛太陡；Go 用 20% 的努力（快速编译+GC），换取了 80% 媲美 Rust 的安全性，这恰好是 AI 迭代的最优解。</p>
<h2>极简主义与“无聊”的胜利</h2>
<p>Go 语言自诞生起，就因为其语法的“无聊”和“死板”（比如缺乏灵活的宏、长期没有泛型、繁琐的错误处理）而饱受争议。然而，在 AI 时代，这种“无聊”却意外地成为了巨大的优势。</p>
<h3>“只有一种做法”的红利</h3>
<p>Python 和 JavaScript 以“灵活”著称。在一个 JS 项目中，有人用 CommonJS，有人用 ES6 Modules；有人用 npm，有人用 pnpm。对于人类来说，这叫“生态繁荣”；但对于 LLM 来说，这叫“状态空间爆炸”（High Entropy）。</p>
<p>Go 是极其“固执”的语言（Opinionated）。</p>
<ul>
<li>格式化代码？只有 gofmt。</li>
<li>怎么处理错误？永远是 if err != nil。</li>
<li>怎么写测试？标准库 testing 包。</li>
</ul>
<p>正如作者指出的：“要求 Agent 格式化 JS 代码，它会去引入一个新工具并尝试配置它；而在 Go 中，它只需要运行 gofmt。”</p>
<p>这种<strong>高度统一的代码风格</strong>，意味着在 LLM 的训练语料库中，Go 代码的“信噪比”极高。模型不需要在多种编程范式中猜测你的偏好，它输出的 Go 代码通常具有高度的同质性和可预测性。</p>
<h3>人类可读性：代码审查的最后防线</h3>
<p>当 AI 成为主要的“代码编写者”时，人类的角色将不可避免地向“代码审查者（Code Reviewer）”倾斜。</p>
<p>如果 AI 生成了一段高度抽象的 Haskell 代码，或者使用了大量宏的 Rust 代码，人类审查者需要耗费极大的脑力去反编译这些逻辑。</p>
<p>而 Go 代码是出了名的“所见即所得”。没有隐藏的控制流，没有复杂的运算符重载。当 AI 生成了几百行 Go 代码时，即使是一位初级开发者，也能相对轻松地顺着逻辑线读懂它在干什么。</p>
<p><strong>在 AI 编程的下半场，“代码易读”将比“代码易写”重要一万倍。</strong></p>
<h2>跨越阵营的交锋：Hacker News 的不同声音</h2>
<p>当然，这篇文章在 Hacker News 上并非一边倒的赞同。不同语言阵营的开发者提出了极其犀利的反思。</p>
<h3>反思一：Python 真的过时了吗？</h3>
<p>Python 拥护者指出，文章混淆了“运行时性能”和“开发生态”。</p>
<p>虽然 Go 在高并发和 I/O 上碾压 Python，但如果 AI Agent 的核心逻辑涉及大量的数据科学计算、复杂的概率模型，或者需要直接调用底层的 C++ 机器学习库，Python 依然是不可替代的粘合剂。对于许多初创团队来说，“让代码先跑起来”远比“让代码跑得快”更重要。</p>
<h3>反思二：类型系统能否取代测试？</h3>
<p>支持函数式语言（如 OCaml, F#）的开发者指出，Go 的类型系统依然过于薄弱。</p>
<p>Go 缺乏代数数据类型（ADT）和模式匹配，导致其虽然能抓住低级语法错误，但难以像 Rust 或 OCaml 那样“在编译期保证业务逻辑状态的正确性”。</p>
<p>对于他们而言，如果 AI 真的足够聪明，应该让 AI 生成具有极强类型约束的代码，把正确性完全交给编译器，而不是像 Go 那样依然需要编写大量的单元测试。</p>
<h3>反思三：长远来看，语言还重要吗？</h3>
<p>这是一个终极的哲学问题：<strong>如果未来 AI 不再犯错，能够零成本生成正确的机器码，高级编程语言还有存在的意义吗？</strong></p>
<p>有评论认为，当模型能力足够强时，我们甚至不需要编译型语言的保护，直接用自然语言（英语）+ LLM 生成运行时的 WebAssembly 可能才是终局。在这个维度上，争论 Go 还是 Python，就像在争论用什么牌子的算盘（意指已经被时代所抛弃的东西）一样没有意义。</p>
<h2>小结：实用主义者的狂欢</h2>
<p><img src="https://tonybai.com/wp-content/uploads/2026/why-go-is-the-best-language-for-ai-agents-2.png" alt="" /></p>
<p>在 AI 技术日新月异的当下，我们往往容易陷入一种对“前沿”的盲目崇拜，认为只有最复杂的语言、最先进的模型才能构建出优秀的系统。</p>
<p>但 Bruin 作者的实践和 Go 社区的繁荣告诉我们另一个故事：工程的本质是权衡（Trade-off）。</p>
<p>Go 并不是世界上最完美的语言，它的类型系统不如 Rust 严谨，它的生态不如 Python 庞大。但它用极致的编译速度、简单的并发模型、出色的内存管理和统一的编码规范，构建了一个<strong>容错率极高</strong>的工程基座。并且在这个基座上，无论是人类还是 AI Agent，都能以最低的“认知摩擦力”输出可靠的工业级代码。</p>
<p>资料链接：</p>
<ul>
<li>https://getbruin.com/blog/go-is-the-best-language-for-agents/</li>
<li>https://news.ycombinator.com/item?id=47222270</li>
</ul>
<hr />
<p><strong>你更相信谁？</strong></p>
<p>在 AI 编程的下半场，语言的地位正在重构。你是坚守 Python 的生态优势，还是更看好 Go 在“基础设施级 Agent”中的爆发？你认同“编译器是 AI 的最佳守门员”这个观点吗？</p>
<p>欢迎在评论区留下你的“阵营宣言”！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p><strong>原「Gopher部落」已重装升级为「Go &amp; AI 精进营」知识星球，快来加入星球，开启你的技术跃迁之旅吧！</strong></p>
<p>我们致力于打造一个高品质的 <strong>Go 语言深度学习</strong> 与 <strong>AI 应用探索</strong> 平台。在这里，你将获得：</p>
<ul>
<li><strong>体系化 Go 核心进阶内容:</strong> 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏，夯实你的 Go 内功。</li>
<li><strong>前沿 Go+AI 实战赋能:</strong> 紧跟时代步伐，学习「Go+AI应用实战」、「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战课」、「OpenClaw实战分享」等，掌握 AI 时代新技能。</li>
<li><strong>星主 Tony Bai 亲自答疑:</strong> 遇到难题？星主第一时间为你深度解析，扫清学习障碍。</li>
<li><strong>高活跃 Gopher 交流圈:</strong> 与众多优秀 Gopher 分享心得、讨论技术，碰撞思想火花。</li>
<li><strong>独家资源与内容首发:</strong> 技术文章、课程更新、精选资源，第一时间触达。</li>
</ul>
<p>衷心希望「Go &amp; AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚，享受技术精进的快乐！欢迎你的加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-and-ai-tribe-zsxq-small-card.jpg" alt="img{512x368}" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/03/07/why-go-is-the-best-language-for-ai-agents/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>金融级基础设施重构：放弃 Rust 拥抱 Go，务实主义的最终胜利？</title>
		<link>https://tonybai.com/2026/02/23/financial-infrastructure-rust-to-go-pragmatism-victory/</link>
		<comments>https://tonybai.com/2026/02/23/financial-infrastructure-rust-to-go-pragmatism-victory/#comments</comments>
		<pubDate>Mon, 23 Feb 2026 01:09:42 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[BackendDevelopment]]></category>
		<category><![CDATA[BorrowChecker]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[CognitiveLoad]]></category>
		<category><![CDATA[ConcurrencyModel]]></category>
		<category><![CDATA[Correctness]]></category>
		<category><![CDATA[DevelopmentEfficiency]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[DistributedSystems]]></category>
		<category><![CDATA[FinancialInfrastructure]]></category>
		<category><![CDATA[GarbageCollection]]></category>
		<category><![CDATA[GC]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[HFT]]></category>
		<category><![CDATA[InterfaceDesign]]></category>
		<category><![CDATA[latency]]></category>
		<category><![CDATA[machinelearning]]></category>
		<category><![CDATA[MemorySafety]]></category>
		<category><![CDATA[ML]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Pragmatism]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[ROI]]></category>
		<category><![CDATA[Rust]]></category>
		<category><![CDATA[SoftwareEngineering]]></category>
		<category><![CDATA[TeamBuilding]]></category>
		<category><![CDATA[TechSelection]]></category>
		<category><![CDATA[借用检查器]]></category>
		<category><![CDATA[内存安全]]></category>
		<category><![CDATA[分布式系统]]></category>
		<category><![CDATA[务实主义]]></category>
		<category><![CDATA[后端开发]]></category>
		<category><![CDATA[团队建设]]></category>
		<category><![CDATA[垃圾回收]]></category>
		<category><![CDATA[并发模型]]></category>
		<category><![CDATA[延迟]]></category>
		<category><![CDATA[开发效率]]></category>
		<category><![CDATA[性能]]></category>
		<category><![CDATA[技术选型]]></category>
		<category><![CDATA[投入产出比]]></category>
		<category><![CDATA[接口设计]]></category>
		<category><![CDATA[机器学习]]></category>
		<category><![CDATA[正确性]]></category>
		<category><![CDATA[认知负荷]]></category>
		<category><![CDATA[软件工程]]></category>
		<category><![CDATA[金融级基础设施]]></category>
		<category><![CDATA[高频交易]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=5934</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/02/23/financial-infrastructure-rust-to-go-pragmatism-victory 大家好，我是Tony Bai。 在系统级编程语言的版图上，Go 与 Rust 的对比与争论从未停歇。一个是崇尚大道至简、开发效率极高的“云原生时代王者”；另一个则是以内存安全、零成本抽象和极致性能著称的“极客新宠”。当这两种哲学碰撞在对安全性、稳定性和低延迟要求极高的金融/交易基础设施领域时，开发者该如何抉择？ 近日，在 Reddit 的 r/golang 社区中，一场由 Python 开发者发起的关于“金融基础设施长期演进：Go 还是 Rust？”的技术讨论引发了广泛关注。这位开发者试图为机器学习（ML）流水线、分布式后端和内部 DevOps 工具选择一门强类型语言，并一度陷入了“是否应该同时学习两者”的焦虑中。 这场社区讨论不仅揭示了两种语言在现代架构中的真实定位，更展现了 Go 社区一贯的“务实主义”工程哲学。本文将深度提炼这场讨论的核心观点，为正处于技术选型十字路口的架构师和开发者提供极具价值的参考。 核心探讨：金融系统中的“快”与“对” 在金融科技（FinTech）和交易系统中，有两个指标至关重要：性能（Performance/Latency）与 正确性（Correctness）。这恰好对应了系统级语言常常被审视的两个维度。 Rust 的诱惑：绝对的控制与“编译即正确” 许多开发者最初被 Rust 吸引，正是因为其在金融领域展现出的“绝对严谨”。 代数数据类型与状态机：社区用户指出，Rust 的表达能力极强。在处理复杂的金融业务逻辑（如订单状态流转、复杂的税务和结算规则）时，Rust 的枚举（Enum）和模式匹配可以迫使开发者在编译期处理所有可能的边缘情况，实现所谓的“使无效状态不可表达”（Make invalid states unrepresentable）。 无数据竞争（Data Race Free）：借用检查器（Borrow Checker）和所有权模型在根本上杜绝了多线程环境下的数据竞争。对于处理资金流水的并发程序而言，这种内存安全性能够极大地降低睡眠被报警惊醒的概率。 无 GC 延迟：针对极度敏感的场景（如做市商系统），Rust 摆脱了垃圾回收器（Garbage Collector）的不可预测性，能够提供稳定、可预测的尾部延迟（Tail Latency）。 然而，正如资深工程师在讨论中指出的：“Rust 的高壁垒不仅体现在初始学习成本上，更体现在它持续要求你的大脑处于高速运转状态。” 在编写普通业务代码时，开发者需要不断与编译器“搏斗”，这在无形中拖慢了业务交付（Shipping）的速度。 Go 的底气：“80% 的性能，20% 的精力” 面对 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/financial-infrastructure-rust-to-go-pragmatism-victory-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/02/23/financial-infrastructure-rust-to-go-pragmatism-victory">本文永久链接</a> &#8211; https://tonybai.com/2026/02/23/financial-infrastructure-rust-to-go-pragmatism-victory</p>
<p>大家好，我是Tony Bai。</p>
<p>在系统级编程语言的版图上，Go 与 Rust 的对比与争论从未停歇。一个是崇尚大道至简、开发效率极高的“云原生时代王者”；另一个则是以内存安全、零成本抽象和极致性能著称的“极客新宠”。当这两种哲学碰撞在对安全性、稳定性和低延迟要求极高的金融/交易基础设施领域时，开发者该如何抉择？</p>
<p>近日，在 Reddit 的 r/golang 社区中，一场由 Python 开发者发起的关于“<a href="https://www.reddit.com/r/golang/comments/1ra0dza/go_vs_rust_for_longterm_systemsfinance/">金融基础设施长期演进：Go 还是 Rust？</a>”的技术讨论引发了广泛关注。这位开发者试图为机器学习（ML）流水线、分布式后端和内部 DevOps 工具选择一门强类型语言，并一度陷入了“是否应该同时学习两者”的焦虑中。</p>
<p>这场社区讨论不仅揭示了两种语言在现代架构中的真实定位，更展现了 Go 社区一贯的“务实主义”工程哲学。本文将深度提炼这场讨论的核心观点，为正处于技术选型十字路口的架构师和开发者提供极具价值的参考。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/paid/system-programming-in-go-pr.png" alt="" /></p>
<h2>核心探讨：金融系统中的“快”与“对”</h2>
<p>在金融科技（FinTech）和交易系统中，有两个指标至关重要：性能（Performance/Latency）与 正确性（Correctness）。这恰好对应了系统级语言常常被审视的两个维度。</p>
<h3>Rust 的诱惑：绝对的控制与“编译即正确”</h3>
<p>许多开发者最初被 Rust 吸引，正是因为其在金融领域展现出的“绝对严谨”。</p>
<ul>
<li>代数数据类型与状态机：社区用户指出，Rust 的表达能力极强。在处理复杂的金融业务逻辑（如订单状态流转、复杂的税务和结算规则）时，Rust 的枚举（Enum）和模式匹配可以迫使开发者在编译期处理所有可能的边缘情况，实现所谓的“使无效状态不可表达”（Make invalid states unrepresentable）。</li>
<li>无数据竞争（Data Race Free）：借用检查器（Borrow Checker）和所有权模型在根本上杜绝了多线程环境下的数据竞争。对于处理资金流水的并发程序而言，这种内存安全性能够极大地降低睡眠被报警惊醒的概率。</li>
<li>无 GC 延迟：针对极度敏感的场景（如做市商系统），Rust 摆脱了垃圾回收器（Garbage Collector）的不可预测性，能够提供稳定、可预测的尾部延迟（Tail Latency）。</li>
</ul>
<p>然而，正如资深工程师在讨论中指出的：“Rust 的高壁垒不仅体现在初始学习成本上，更体现在它持续要求你的大脑处于高速运转状态。” 在编写普通业务代码时，开发者需要不断与编译器“搏斗”，这在无形中拖慢了业务交付（Shipping）的速度。</p>
<h3>Go 的底气：“80% 的性能，20% 的精力”</h3>
<p>面对 Rust 强大的理论优势，Go 社区给出的回应并不是在极限性能上去硬碰硬，而是打出了一张工程学上的王牌：投入产出比（ROI）。</p>
<ul>
<li>极速的开发与迭代：“如果你的目标是尽快发布产品（Ship fast），同时保持系统的可靠性，Go 是完美的折中。” Go 语言的语法极简，没有复杂的生命周期标注，这使得开发者可以把 100% 的精力放在业务逻辑和系统架构上，而不是讨好编译器。</li>
<li>完美的 I/O 并发模型：金融系统的很大一部分工作并非重度 CPU 计算，而是网络 I/O（如对接外部交易所 API、读取数据库、微服务间通信）。Go 内置的 goroutine 提供了极其廉价的上下文切换机制。一位用户精辟地总结：“在处理高度并发或重度 I/O 阻塞的操作时，Go 是无敌的。而在 Rust 中构建高并发的异步（Async）应用，需要极高的经验值，但在 Go 中这就像呼吸一样自然。”</li>
<li>足够好的性能与 GC：虽然 Go 有垃圾回收机制，但经过十多年的演进，Go 的 GC 停顿时间已经达到了亚毫秒级。对于 99% 的金融应用（如支付网关、账单系统、风控后端）来说，Go 的性能已经“快到了性能盈余”的地步。社区用户坦言：“除非你是在证券交易所做内部的高频交易（HFT），否则 Go 的速度绝对绰绰有余。”</li>
</ul>
<h2>领域决定边界：基础设施与业务逻辑的解耦</h2>
<p>讨论中一个非常核心的洞见是：不要试图用一种语言解决所有问题，而是要看清具体领域的边界。楼主的背景是 Python，主要涉及 ML 流水线。这引出了现代架构中非常经典的一种组合模式。</p>
<h3>Python + Go：现代数据驱动架构的“王炸”组合</h3>
<ul>
<li>Python 主宰数据与模型：在机器学习、量化分析和数据科学领域，Python 的生态（Pandas, NumPy, PyTorch）具有不可撼动的统治地位。强行用 Go 或 Rust 去重写模型训练或复杂的矩阵运算，被社区公认为“过早优化”和“重复造轮子”。</li>
<li>Go 主宰服务与编排：当模型训练完成需要部署上线，或者需要构建处理海量请求的 API 网关、数据搬运管道、以及后端微服务时，Python 的 GIL（全局解释器锁）和性能瓶颈就会显现。此时，引入 Go 作为基础设施层（Infrastructure Layer）是最完美的互补。</li>
</ul>
<p>这种架构下，系统被清晰地划分为：Go 负责将数据又快又稳地搬运和路由，Python（在底层 C/C++ 的加持下）负责纯粹的数学和模型计算。这种解耦使得整个系统既享受了 Python 的生态红利，又获得了 Go 在分布式系统上的强悍工程能力。</p>
<h3>真正的 HFT（高频交易）属于谁？</h3>
<p>不可忽视的是，当讨论深入到金融领域的最底端——高频交易（HFT）时，社区展现出了极度客观的技术视野。</p>
<p>多位业内人士指出，在纳秒必争的超低延迟交易领域，C++ 依然是绝对的霸主。尽管 Rust 在试图切入这一市场，但 C++ 在传统金融领域积累的庞大库、成熟的生态以及直接操作硬件的能力，短期内难以被撼动。因此，如果业务的核心真的是 HFT，那么 Go 和 Rust 可能都不是最优解。这就进一步确认了 Go 的主战场：<strong>高吞吐的分布式后端与云原生基础设施。</strong></p>
<h2>隐性成本：认知负荷、团队建设与代码维护</h2>
<p>在架构决策中，语言的特性往往只占 50%，另外 50% 则是<strong>关于人的管理</strong>。这也是本次社区讨论中，Go 获得压倒性支持的关键原因。</p>
<h3>代码的生命周期与可修改性</h3>
<p>“在商业应用中，我更看重随着时间的推移，修改代码有多难。业务需求在不断变化，代码也必须随之改变。”</p>
<ul>
<li>Go 的修改成本极低：Go 的代码结构扁平，没有复杂的隐式抽象。这使得重构和修改极其快速。Go 的接口（Interface）设计是隐式的（Duck Typing），在拆分微服务或调整模块时，不需要像严格继承体系那样大动干戈。</li>
<li>Rust 的“牵一发而动全身”：Rust 高度严格的类型系统是一把双刃剑。虽然它保证了修改后的代码几乎不会出错，但在快速迭代期，添加一个新功能往往意味着要重构一大部分的生命周期标注和类型关系，这对于需要快速响应市场变化的初创项目来说是致命的。</li>
</ul>
<h3>团队招聘与代码交接</h3>
<p>“如果你用 Rust 构建了一个工具，当系统在半夜发生故障时，团队里的其他人能轻易地看懂代码并修复它吗？”</p>
<p>Go 的创造者之一 Rob Pike 曾明确表示，Go 的设计初衷就是为了解决 Google 内部大型团队的协作问题。Go 的语法少、规范统一（gofmt），被称为“没有魔法的语言”。一个有其他语言基础的程序员，通常只需一两周就能熟练上手 Go 并提交生产代码。</p>
<p>相比之下，熟练的 Rust 开发者在市场上不仅稀缺，而且薪资高昂。对于一家非底层技术驱动的金融公司而言，使用 Go 可以极大地降低招聘门槛和团队代码交接的风险。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/financial-infrastructure-rust-to-go-pragmatism-victory-2.png" alt="" /></p>
<h2>小结：务实主义的胜利</h2>
<p>回到这位发帖者的终极问题：“我应该同时深入学习 Go 和 Rust 吗？”</p>
<p>社区给出的答案异常一致：<strong>绝对不要。</strong> 尤其是在项目初期。同时学习两门底层逻辑截然不同的语言，不仅会带来巨大的认知撕裂，还会严重拖慢项目进度（Shipping speed）。</p>
<p>最终，这位发帖者更新了他的决定：<strong>选择 Go。</strong></p>
<blockquote>
<p>“我不想在开始阶段就陷入困境，既然我是独立开发，我开始觉得 Go 才是正道。对于沉重的数学计算，我会继续让 Python 负责。我意识到 Go 真的非常好用，只要我懂得正确使用它，它能在所有的用例中大显身手。此外，Go 社区是我见过最友好的社区之一，你们太棒了！”</p>
</blockquote>
<p>在 AI、区块链、量化金融等技术泡沫层出不穷的今天，技术选型很容易陷入“追逐时髦”（Hype Driven Development）的陷阱。Rust 无疑是一门伟大的语言，代表了系统编程的未来探索。然而，Go 语言的伟大之处在于它始终保持着<strong>极其清醒的工程边界感</strong>。</p>
<p>它不追求类型理论的极致完美，也不苛求消除最后百分之一的性能损耗，它追求的是：在开发者心智负担、编译速度、运行性能、并发模型和部署便利性之间，找到一个无可挑剔的全局最优解。</p>
<p>对于现代分布式系统、网络服务和金融后端基础设施而言，Go 依然是那个能够让你“早点下班、安心睡觉”的最优选择。这也是务实主义在工程世界里，又一次漂亮的胜利。</p>
<p>资料链接：https://www.reddit.com/r/golang/comments/1ra0dza/go_vs_rust_for_longterm_systemsfinance/</p>
<hr />
<p><strong>你怎么选？</strong></p>
<p>软件工程永远是权衡的艺术。在你看来，对于非高频交易的后端业务，Rust 带来的安全性是否足以抵消它的开发成本？如果你现在接手一个新项目，你会优先选择“能让你早点下班”的 Go 吗？</p>
<p>欢迎在评论区分享你的选型“心法”！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/02/23/financial-infrastructure-rust-to-go-pragmatism-victory/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AI 基础设施的语言之争：为何构建 LLM 网关时，我们放弃了 Python 选择了 Go？</title>
		<link>https://tonybai.com/2026/02/18/why-we-chose-go-over-python-for-llm-gateways/</link>
		<comments>https://tonybai.com/2026/02/18/why-we-chose-go-over-python-for-llm-gateways/#comments</comments>
		<pubDate>Tue, 17 Feb 2026 23:43:31 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AgenticCoding]]></category>
		<category><![CDATA[AIInfrastructure]]></category>
		<category><![CDATA[AI基础设施]]></category>
		<category><![CDATA[benchmark]]></category>
		<category><![CDATA[ConcurrencyModel]]></category>
		<category><![CDATA[ContextSwitching]]></category>
		<category><![CDATA[GIL]]></category>
		<category><![CDATA[GMPScheduling]]></category>
		<category><![CDATA[GMP调度]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[goroutine]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[I/O密集型]]></category>
		<category><![CDATA[InferenceService]]></category>
		<category><![CDATA[IObound]]></category>
		<category><![CDATA[LanguageWar]]></category>
		<category><![CDATA[LLMGateway]]></category>
		<category><![CDATA[LLM网关]]></category>
		<category><![CDATA[MemoryEfficiency]]></category>
		<category><![CDATA[ModelTraining]]></category>
		<category><![CDATA[orchestration]]></category>
		<category><![CDATA[PerformanceBottleneck]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[SandwichArchitecture]]></category>
		<category><![CDATA[SoftwareEngineering]]></category>
		<category><![CDATA[StaticBinary]]></category>
		<category><![CDATA[三明治架构]]></category>
		<category><![CDATA[上下文切换]]></category>
		<category><![CDATA[全局解释器锁]]></category>
		<category><![CDATA[内存效率]]></category>
		<category><![CDATA[基准测试]]></category>
		<category><![CDATA[并发模型]]></category>
		<category><![CDATA[应用编排]]></category>
		<category><![CDATA[性能瓶颈]]></category>
		<category><![CDATA[推理服务]]></category>
		<category><![CDATA[智能体编程]]></category>
		<category><![CDATA[模型训练]]></category>
		<category><![CDATA[语言之争]]></category>
		<category><![CDATA[软件工程]]></category>
		<category><![CDATA[静态二进制]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=5905</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/02/18/why-we-chose-go-over-python-for-llm-gateways 大家好，我是Tony Bai。 在 2026 年的今天，人工智能早已走出了实验室，成为企业级应用的核心驱动力。Python，凭借其在机器学习领域的绝对统治地位——拥有 PyTorch、TensorFlow、Hugging Face 等无可匹敌的生态系统——长期以来被视为 AI 开发的“默认语言”。 然而，随着 AI 应用从模型训练（Training）走向推理服务（Inference）和应用编排（Orchestration），工程重心发生了微妙的转移。当我们谈论模型本身时，Python 是王者；但当我们谈论承载模型流量的基础设施——网关、代理、路由器时，Python 还是最佳选择吗？ 近日，开源 LLM 网关项目 Bifrost 的维护者在 Reddit 上分享了一篇题为《Why we chose Go over Python for building an LLM gateway》的技术复盘，引发了社区的强烈反响。他们放弃了拥有 LiteLLM 等成熟竞品的 Python 生态，转而使用 Go 重写了核心网关。结果令人咋舌：延迟降低了约 700 倍，内存占用降低了 68%，吞吐量提升了 3 倍。 这场技术选型的背后，折射出的是 AI 工程化进入深水区后，对并发模型、资源效率与部署架构的重新审视。 Python 的“舒适区”与“性能墙” 在项目的初期，选择 Python 似乎是理所当然的。 1. [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/why-we-chose-go-over-python-for-llm-gateways-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/02/18/why-we-chose-go-over-python-for-llm-gateways">本文永久链接</a> &#8211; https://tonybai.com/2026/02/18/why-we-chose-go-over-python-for-llm-gateways</p>
<p>大家好，我是Tony Bai。</p>
<p>在 2026 年的今天，人工智能早已走出了实验室，成为企业级应用的核心驱动力。Python，凭借其在机器学习领域的绝对统治地位——拥有 PyTorch、TensorFlow、Hugging Face 等无可匹敌的生态系统——长期以来被视为 AI 开发的“默认语言”。</p>
<p>然而，随着 AI 应用从模型训练（Training）走向推理服务（Inference）和应用编排（Orchestration），工程重心发生了微妙的转移。当我们谈论模型本身时，Python 是王者；但当我们谈论<strong>承载模型流量的基础设施</strong>——网关、代理、路由器时，Python 还是最佳选择吗？</p>
<p>近日，<a href="https://github.com/maximhq/bifrost">开源 LLM 网关项目 Bifrost</a> 的维护者在 Reddit 上分享了一篇题为《<a href="https://www.reddit.com/r/golang/comments/1r27pqx/why_we_chose_go_over_python_for_building_an_llm/">Why we chose Go over Python for building an LLM gateway</a>》的技术复盘，引发了社区的强烈反响。他们放弃了拥有 LiteLLM 等成熟竞品的 Python 生态，转而使用 Go 重写了核心网关。结果令人咋舌：延迟降低了约 700 倍，内存占用降低了 68%，吞吐量提升了 3 倍。</p>
<p>这场技术选型的背后，折射出的是 AI 工程化进入深水区后，对<a href="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzIyNzM0MDk0Mg==&amp;action=getalbum&amp;album_id=4105816518230016005#wechat_redirect">并发模型</a>、资源效率与部署架构的重新审视。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/paid/go-concurrency-mental-model-qr.png" alt="" /></p>
<h2>Python 的“舒适区”与“性能墙”</h2>
<p>在项目的初期，选择 Python 似乎是理所当然的。</p>
<p><strong>1. 生态惯性与“胶水”优势</strong></p>
<p>绝大多数 AI 工程师都是 Python Native。从 LangChain 到 LlamaIndex，几乎所有的 Agent 开发框架都优先支持 Python。使用 Python 构建网关，意味着可以直接复用现有的库，甚至可以直接挂载一些轻量级的 Python 逻辑来处理 Embeddings 或 RAG（检索增强生成）流程。FastAPI 的易用性更是让开发者能在几分钟内搭建起一个服务。</p>
<p><strong>2. 遭遇瓶颈：网关的本质是 I/O</strong></p>
<p>然而，LLM 网关的业务属性决定了它的性能痛点。与计算密集型（CPU-bound）的模型推理不同，网关是典型的 I/O 密集型应用。它的核心职责是：</p>
<ul>
<li>接收成千上万的客户端请求。</li>
<li>将请求转发给上游提供商（如 OpenAI, Anthropic, 或自建的 vLLM）。</li>
<li>等待上游响应（这是最耗时的环节，LLM 的首字延迟 TTFT 通常在秒级）。</li>
<li>将流式响应（SSE）回传给客户端。</li>
</ul>
<p>在这个过程中，网关绝大部分时间都在“等待”。</p>
<p><strong>3. Python 的并发痛点</strong></p>
<p>Bifrost 团队在测试中发现，当并发请求数达到 500-1000 RPS（每秒请求数）时，Python 的瓶颈开始显现。</p>
<ul>
<li>GIL（全局解释器锁）的幽灵：虽然 Python 的 asyncio 可以处理 I/O 并发，但 GIL 依然限制了多核 CPU 的利用率。对于需要处理大量并发连接、同时可能涉及少量数据处理（如 Token 计数、PII 过滤）的网关来说，线程竞争（Thread Contention）成为了不可忽视的开销。</li>
<li>昂贵的上下文切换：在 Python 中维持数千个并发连接，其上下文切换的开销远高于编译型语言。</li>
</ul>
<h2>Go 的降维打击——数据背后的技术真相</h2>
<p>Bifrost 团队最终选择了 Go。这一决定并非出于对语言的偏好，而是基于冷冰冰的 Benchmark 数据。让我们深入分析他们披露的核心指标。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/why-we-chose-go-over-python-for-llm-gateways-2.png" alt="" /></p>
<h3>延迟（Latency）：微秒与毫秒的鸿沟</h3>
<blockquote>
<p><strong>数据对比</strong>：<br />
  *   <strong>Bifrost (Go)</strong>: ~11 微秒 (0.011ms) / 请求<br />
  *   <strong>LiteLLM (Python)</strong>: ~8 毫秒 / 请求</p>
</blockquote>
<p>这是一个惊人的 <strong>700 倍</strong> 差距。</p>
<p>虽然 8 毫秒在人类感知中似乎微不足道，但在高并发架构中，这被称为“开销放大”。</p>
<ul>
<li>累积效应：在一个复杂的 AI Agent 工作流中，可能涉及几十次 LLM 调用。如果每一层网关都增加 8ms 的延迟，累积起来就是可感知的卡顿。</li>
<li>高负载下的劣化：在 10,000 个并发请求下，Go 引入的总处理时间仅为 110ms，而 Python 方案则产生了惊人的 80 秒总 CPU 时间开销。这意味着 Python 方案需要消耗更多的 CPU 核心来维持同样的响应速度，否则请求就会排队，导致尾部延迟（Tail Latency）飙升。</li>
</ul>
<p>此外，Go 的 net/http 标准库在处理 HTTP 请求时经过了极致优化。Go 不需要像 Python 那样依赖 ASGI/WSGI 服务器（如 Uvicorn），其原生的 HTTP 处理能力配合 Goroutine，使得每个请求的内存分配和 CPU 周期都降到了最低。</p>
<h3>并发模型：Goroutine vs Asyncio</h3>
<blockquote>
<p><strong>架构对比</strong>：<br />
  *   <strong>Go</strong>: 10,000 个 Goroutines，每个仅占用 ~2KB 栈空间。<br />
  *   <strong>Python</strong>: 受限于 OS 线程开销或 Event Loop 的单核瓶颈。</p>
</blockquote>
<p>LLM 网关的特殊性在于长连接。LLM 的流式输出可能持续数秒甚至更久。这意味着网关必须同时维护成千上万个活跃连接。</p>
<p>Go 的 GMP（Goroutine-Machine-Processor）调度模型天生适合这种场景。成千上万个 Goroutine 可以复用少量的系统线程，上下文切换由 Go Runtime 在用户态极速完成，几乎不消耗系统内核资源。</p>
<p>相比之下，Python 即使使用了 uvloop，在面对海量并发连接的数据搬运时，其解释器的开销依然是一个沉重的包袱。</p>
<h3>内存效率与成本</h3>
<blockquote>
<p><strong>数据对比</strong>：<br />
  *   <strong>Go</strong>: 内存占用降低 ~68%。<br />
  *   <strong>生产环境</strong>: Go 跑在 t3.medium (2 vCPU, 4GB) 上即可；Python 则需要 t3.xlarge。</p>
</blockquote>
<p>对于大规模部署 AI 服务的企业来说，这意味着基础设施成本直接减半。</p>
<p>Python 的动态类型系统和垃圾回收机制导致其对象内存占用较大。而 Go 的结构体布局紧凑，且编译器能进行逃逸分析（Escape Analysis），将大量对象分配在栈上而非堆上，从而显著降低了 GC 压力和内存占用。</p>
<h2>社区深度探讨——AI 时代的语言版图重构</h2>
<p>这篇帖子在 r/golang 引发了极高质量的讨论，评论区揭示了行业内更深层次的趋势。</p>
<h3>“AI 能够写代码”改变了竞争规则</h3>
<p>过去，Python 的一大优势是“开发效率高”。写 Python 代码通常比写 Go 或 Rust 快。</p>
<p>但在 2026 年，“Agentic Coding”（即利用 AI Coding Agent 辅助编程）已经成为主流。</p>
<p>有开发者指出：“LLM 让编写 Rust 和 Go 变得非常高效，你完全可以享受到高性能语言的红利，而不用支付编写它们的‘学习成本’。”</p>
<p>这是一个极其深刻的洞察。</p>
<ul>
<li>Rust 的借用检查器：以前是新手的噩梦，现在 LLM 可以很好地处理生命周期标注。</li>
<li>Go 的样板代码：if err != nil 虽然繁琐，但 Copilot/Cursor/Claude Code等 可以一键生成。</li>
</ul>
<p>当“编写代码”不再是瓶颈时，“运行时性能”和“稳定性”的权重就被无限放大了。这进一步削弱了 Python 在后端基础设施层的竞争力。</p>
<h3>Rust 还是 Go？</h3>
<p>既然要高性能，为什么不直接上 Rust？</p>
<p>评论区对此展开了激辩。虽然 Rust 在理论上拥有比 Go 更高的性能上限和内存安全性（无 GC），但 Go 在“开发效率”与“运行效率”之间找到了完美的平衡点。</p>
<ul>
<li>Rust: 适合构建数据库、搜索引擎内核等对延迟极其敏感且逻辑复杂的底层组件。但 Rust 的“认知负担”依然较重，且编译速度较慢。</li>
<li>Go: 提供了 80% 的 Rust 性能，但只有 20% 的开发难度。对于网关、代理这类中间件，Go 的标准库（特别是 net/http）极其成熟，编译速度极快，且自带 GC 能让开发者从内存管理的细节中解脱出来，专注于业务逻辑（如限流、计费）。</li>
</ul>
<p>对于大多数 AI 网关场景，Go 是性价比最高的选择。</p>
<h3>Python 的归宿：模型与胶水</h3>
<p>这是否意味着 Python 将被淘汰？绝不。</p>
<p>社区共识非常明确：Python 的护城河在于 ML 生态。</p>
<ul>
<li>模型训练与微调：PyTorch/JAX 无可替代。</li>
<li>数据科学与探索：Jupyter Notebook 是数据科学家的后花园。</li>
<li>快速原型开发：在验证想法阶段，Python 依然是最快的。</li>
</ul>
<p>但在生产环境部署（Production Serving）阶段，架构正在发生分离：</p>
<ul>
<li>控制平面（Control Plane）：由 Go/Rust 接管，负责流量调度、鉴权、日志、监控。</li>
<li>数据平面（Data Plane）：核心推理引擎（如 vLLM）虽然内部可能有 C++/CUDA 优化，但外层接口仍常由 Python 封装。</li>
</ul>
<h2>Go 在 AI 领域的未来展望</h2>
<p>Bifrost 的案例只是冰山一角。我们正在目睹 Go 语言在 AI 领域的“新基建”运动。</p>
<h3>静态二进制文件的魅力</h3>
<p>Deployment simplicity 是作者提到的另一个关键点。</p>
<p>部署 Python 应用通常意味着：配置 Docker -> 安装 Python -> pip install requirements.txt -> 解决依赖冲突 -> 虚拟环境管理。</p>
<p>而部署 Go 应用：COPY bifrost /usr/local/bin/ -> Run。</p>
<p>在容器化和 K8s 盛行的今天，Go 的静态链接二进制文件极大地简化了 CI/CD 流程，减小了镜像体积，提升了冷启动速度（这对于 Serverless AI 推理尤为重要）。</p>
<h3>AI 专有工具链的完善</h3>
<p>虽然 Go 在 Tensor 操作库上不如 Python 丰富，但在应用层工具上正在迅速补齐。</p>
<ul>
<li>LangChainGo: 社区正在移植 LangChain 的核心能力。</li>
<li>Vector Database Clients: Milvus, Weaviate, Pinecone 等向量数据库都有优秀的 Go SDK。</li>
<li>主流大模型 GenAI SDK: 像Google等主流大模型厂商官方对 Go 的支持力度都很大，Gemini、Claude、OpenAI 等模型的 Go SDK 体验都还不错。</li>
</ul>
<h3>架构师的决策建议</h3>
<p>如果你正在构建一个 AI 应用平台：</p>
<ul>
<li>不要用 Python 写网关：不要让 GIL 成为你高并发路上的绊脚石。</li>
<li>不要用 Go 写模型训练：不要试图挑战 PyTorch 的地位，那是徒劳的。</li>
<li>采用“三明治架构”：
<ul>
<li>上层：Go 处理高并发 HTTP 请求、WebSocket、SSE。</li>
<li>中层：Go 处理业务逻辑、数据库交互、Redis 缓存。</li>
<li>底层：Python/C++ 容器专门负责模型推理，通过 gRPC 与 Go 层通信。</li>
</ul>
</li>
</ul>
<h2>小结</h2>
<p>Bifrost 从 Python 到 Go 的迁移，不仅仅是一次代码重写，更是一次架构理念的升级。它证明了在 AI 浪潮中，基础设施的性能与模型的智能同等重要。</p>
<p>随着 LLM 应用规模的爆发式增长，计算成本和响应延迟将成为企业关注的焦点。Go 语言凭借其高效的并发模型、极低的资源占用和极简的部署体验，正在成为 AI 基础设施层的“事实标准”。</p>
<p>对于 Gopher 而言，这是一个最好的时代。我们不需要成为算法专家，只需要发挥 Go 语言最擅长的能力——构建高性能、高可靠的管道，就能在 AI 时代占据不可或缺的一席之地。</p>
<p>资料链接：https://www.reddit.com/r/golang/comments/1r27pqx/why_we_chose_go_over_python_for_building_an_llm/</p>
<hr />
<p><strong>你认为 Python 会被“边缘化”吗？</strong></p>
<p>随着 Agentic Coding 的普及，高性能语言的入门门槛正在消失。在你的 AI 实践中，是否也感受到了 Python 在生产部署时的无奈？你认为 Go 在 AI 领域还会攻下哪些阵地？</p>
<p>欢迎在评论区分享你的看法！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/02/18/why-we-chose-go-over-python-for-llm-gateways/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Go 微服务重构实录：当后端性能提升 10 倍，移动端体验为何反而崩塌？</title>
		<link>https://tonybai.com/2026/02/13/go-microservices-refactoring-10x-backend-vs-mobile-collapse/</link>
		<comments>https://tonybai.com/2026/02/13/go-microservices-refactoring-10x-backend-vs-mobile-collapse/#comments</comments>
		<pubDate>Fri, 13 Feb 2026 00:10:54 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[APIAggregation]]></category>
		<category><![CDATA[API聚合]]></category>
		<category><![CDATA[BackendPerformance]]></category>
		<category><![CDATA[Batching]]></category>
		<category><![CDATA[BFFPattern]]></category>
		<category><![CDATA[BFF模式]]></category>
		<category><![CDATA[Debouncing]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[Fiber]]></category>
		<category><![CDATA[FrameDrop]]></category>
		<category><![CDATA[FullstackPerspective]]></category>
		<category><![CDATA[GlobalInterpreterLock]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoMicroservices]]></category>
		<category><![CDATA[goroutines]]></category>
		<category><![CDATA[Go微服务]]></category>
		<category><![CDATA[HyrumsLaw]]></category>
		<category><![CDATA[implicitdependency]]></category>
		<category><![CDATA[MobileExperience]]></category>
		<category><![CDATA[P95Latency]]></category>
		<category><![CDATA[P95延迟]]></category>
		<category><![CDATA[PerformanceBoost]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Refactoring]]></category>
		<category><![CDATA[RenderingPipeline]]></category>
		<category><![CDATA[StateManagement]]></category>
		<category><![CDATA[SystemDesign]]></category>
		<category><![CDATA[Throughput]]></category>
		<category><![CDATA[UserExperience]]></category>
		<category><![CDATA[VisionTesting]]></category>
		<category><![CDATA[ZeroAllocation]]></category>
		<category><![CDATA[全局解释器锁]]></category>
		<category><![CDATA[全链路视角]]></category>
		<category><![CDATA[协程]]></category>
		<category><![CDATA[后端性能]]></category>
		<category><![CDATA[吞吐量]]></category>
		<category><![CDATA[性能提升]]></category>
		<category><![CDATA[批处理]]></category>
		<category><![CDATA[掉帧]]></category>
		<category><![CDATA[海勒姆定律]]></category>
		<category><![CDATA[渲染管线]]></category>
		<category><![CDATA[状态管理]]></category>
		<category><![CDATA[用户体验]]></category>
		<category><![CDATA[移动端体验]]></category>
		<category><![CDATA[系统设计]]></category>
		<category><![CDATA[视觉测试]]></category>
		<category><![CDATA[重构]]></category>
		<category><![CDATA[防抖]]></category>
		<category><![CDATA[隐性依赖]]></category>
		<category><![CDATA[零内存分配]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=5878</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/02/13/go-microservices-refactoring-10x-backend-vs-mobile-collapse 大家好，我是Tony Bai。 在软件工程的世界里，“快”通常被视为绝对的褒义词。我们追求更低的延迟、更高的吞吐量、更少的 CPU 占用。当一个团队决定将遗留的 Python 单体应用重构为 Go 微服务时，他们的目标显而易见：性能提升。 然而，最近在 Go 开发者社区（r/golang）引发热议的一个真实案例，却给所有追求极致性能的架构师和开发者泼了一盆冷水。发帖人分享了一个令人咋舌的经历：他们的团队花费四个月时间，成功将核心 API 从 Django 迁移到了 Go（使用 Fiber 框架）。结果是梦幻般的：P95 延迟从 180ms 骤降至 14ms，吞吐量翻了三倍，CPU 资源节省了 60%。 CTO 发了全员通告庆祝，后端团队沉浸在成功的喜悦中。但在两周后，移动端团队却发出了红色警报：App 变得卡顿、掉帧，甚至导致安卓设备电量疯狂消耗。 后端性能提升了 10 倍，用户体验却发生了退化。这听起来像是一个悖论，但其背后隐藏着深刻的系统设计原理和软件工程教训。本文将深入剖析这一案例，探讨当“速度”成为一种破坏力时，我们该如何应对。 完美的重构与意料之外的崩溃 从 Django 到 Go 的跨越 该团队的重构背景在业界非常典型。随着业务增长，基于 Python/Django 的单体应用逐渐显露出性能瓶颈。Python 的 GIL（全局解释器锁）以及动态语言的特性，在处理高并发请求时往往力不从心。 选择 Go 语言进行重构是极其合理的决策。Go 语言天生具备高并发处理能力（Goroutines），静态编译带来的执行效率，以及相对更低的内存占用，使其成为构建云原生微服务的首选。 团队选择了 Fiber 框架，这是 Go 生态中以高性能著称的 Web [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/go-microservices-refactoring-10x-backend-vs-mobile-collapse-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/02/13/go-microservices-refactoring-10x-backend-vs-mobile-collapse">本文永久链接</a> &#8211; https://tonybai.com/2026/02/13/go-microservices-refactoring-10x-backend-vs-mobile-collapse</p>
<p>大家好，我是Tony Bai。</p>
<p>在软件工程的世界里，“快”通常被视为绝对的褒义词。我们追求更低的延迟、更高的吞吐量、更少的 CPU 占用。当一个团队决定将遗留的 Python 单体应用重构为 Go 微服务时，他们的目标显而易见：性能提升。</p>
<p>然而，最近在 Go 开发者社区（r/golang）引发热议的<a href="https://www.reddit.com/r/golang/comments/1r2n5ji/our_go_microservice_was_10x_faster_than_the_old/">一个真实案例</a>，却给所有追求极致性能的架构师和开发者泼了一盆冷水。发帖人分享了一个令人咋舌的经历：他们的团队花费四个月时间，成功将核心 API 从 Django 迁移到了 Go（使用 Fiber 框架）。结果是梦幻般的：P95 延迟从 180ms 骤降至 14ms，吞吐量翻了三倍，CPU 资源节省了 60%。</p>
<p>CTO 发了全员通告庆祝，后端团队沉浸在成功的喜悦中。但在两周后，移动端团队却发出了红色警报：App 变得卡顿、掉帧，甚至导致安卓设备电量疯狂消耗。</p>
<p>后端性能提升了 10 倍，用户体验却发生了退化。这听起来像是一个悖论，但其背后隐藏着深刻的系统设计原理和软件工程教训。本文将深入剖析这一案例，探讨当“速度”成为一种破坏力时，我们该如何应对。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/paid/api-design-pattern-and-implementation-qr.png" alt="" /></p>
<h2>完美的重构与意料之外的崩溃</h2>
<h3>从 Django 到 Go 的跨越</h3>
<p>该团队的重构背景在业界非常典型。随着业务增长，基于 Python/Django 的单体应用逐渐显露出性能瓶颈。Python 的 GIL（全局解释器锁）以及动态语言的特性，在处理高并发请求时往往力不从心。</p>
<p>选择 Go 语言进行重构是极其合理的决策。Go 语言天生具备高并发处理能力（Goroutines），静态编译带来的执行效率，以及相对更低的内存占用，使其成为构建云原生微服务的首选。</p>
<p>团队选择了 Fiber 框架，这是 Go 生态中以高性能著称的 Web 框架，基于 Fasthttp 构建，旨在追求极致的零内存分配（Zero Allocation）和极速响应。</p>
<p>重构后的 Benchmark 数据证明了决策的正确性：</p>
<ul>
<li><strong>P95 Latency</strong>: 180ms -> 14ms（提升约 12 倍）</li>
<li><strong>Throughput</strong>: 3x（吞吐量翻倍）</li>
<li><strong>Resource</strong>: CPU -60%（成本大幅降低）</li>
</ul>
<p>从后端工程师的 KPI 来看，这是一场完美的胜利。</p>
<h3>移动端的“蝴蝶效应”</h3>
<p>然而，系统是一个整体。当后端交付了“法拉利引擎”般的 API 时，前端（React Native + Redux）却依然是那辆为“拖拉机”设计的旧车。</p>
<p>全量上线两周后，问题集中爆发：</p>
<ol>
<li>交互卡顿：用户在滚动 Feed 流时出现明显的掉帧。</li>
<li>视觉不稳定：页面元素加载过快，导致屏幕闪烁，给人一种“未在大脑中处理完毕”的错觉。</li>
<li>设备发热与耗电：尤其在中低端 Android 设备上，电池消耗显著增加。</li>
</ol>
<p>移动端 Team Lead 对此感到困惑：API 响应客观上变快了，理论上 App 的数据加载应该更丝滑，为什么体验反而劣化了？</p>
<h2>深度复盘——当“慢”成为一种隐性依赖</h2>
<p>经过一周的排查，团队终于找到了问题的根源，答案简单却令人哭笑不得：前端架构是隐式建立在“后端很慢”这一假设之上的。</p>
<h3>隐性依赖</h3>
<p>在旧的架构中，Django API 的响应速度较慢（约 150ms &#8211; 200ms）。由于网络延迟和处理时间，客户端发出的连续请求之间天然存在着“时间间隙”。</p>
<p>移动端的状态管理层（基于 React Native 和旧版 Redux）适应了这种节奏。它假设数据会以“人类可感知的速度” 陆续到达。这种慢速响应在无意中起到了一种天然的节流（Throttling）作用。</p>
<h3>渲染管线的崩溃</h3>
<p>当后端切换到 Go 之后，情况发生了质变。</p>
<p>假设一个典型的页面初始化需要调用 3 个 API 接口：User Profile、Feed Data、Notifications。</p>
<ul>
<li>在 Python 时代：这 3 个请求串行或并行发出，由于服务器处理慢，它们返回的时间点较为分散，总耗时可能在 500ms 左右。Redux 接收到第一个响应，更新 State，触发 React 重新渲染（Re-render）；几百毫秒后，第二个响应到达，再次触发渲染。UI 线程有足够的呼吸时间。</li>
<li>在 Go 时代：这 3 个请求几乎在瞬间完成，总耗时不到 50ms。</li>
</ul>
<p>对于 React Native 的渲染桥（Bridge）和主线程来说，这意味着在极短的时间窗口内，连续收到了 3 次密集的状态更新指令。</p>
<p>由于该团队使用的是旧版 Redux（未使用 RTK Query 等现代缓存/批处理工具），每一次 API 返回都触发了一个 dispatch 动作，进而触发一次完整的 React 组件树 Diff 和渲染过程。</p>
<p><strong>后果是灾难性的：</strong></p>
<ol>
<li>UI 线程阻塞：3 次高计算量的 Re-render 在几十毫秒内连续发生，瞬间占满了 JS 线程和 UI 线程的资源。</li>
<li>React Native Bridge 拥堵：大量的序列化数据在 JS 和 Native 之间传输，导致通信通道“窒息”。</li>
<li>动画丢帧：此时如果用户正在滑动列表，GPU 和 CPU 都在处理布局计算，无法响应滑动手势，导致直观的“卡顿”。</li>
</ol>
<p>这就好比你习惯了有人每隔 10 秒给你递一块砖头让你砌墙，突然间，对方换成了机关枪，一秒钟向你发射 100 块砖头，你不仅接不住，还会被砸伤。</p>
<h2>技术层面的反思与海勒姆定律</h2>
<p>这个案例是海勒姆定律（Hyrum&#8217;s Law）的完美教科书示例。</p>
<blockquote>
<p><strong>海勒姆定律</strong>：<br />
  当一个 API 有足够多的用户时，你在契约（Contract）中承诺什么并不重要：你系统所有的<strong>可观测行为（Observable Behaviors）</strong>都将被某些用户所依赖。</p>
</blockquote>
<p>在这个案例中，API 文档（契约）从未承诺“响应时间必须大于 100ms”。但是，“响应慢”是旧系统的可观测行为。移动端代码（有意或无意地）依赖了这个行为来实现流畅的渲染流。当 Go 重构改变了这一行为（尽管是向好的方向改变），它实际上破坏了系统间的“隐性契约”，导致了破坏性的变更。</p>
<p><strong>为什么中低端设备受害最深？</strong></p>
<p>发帖人提到，他们在开发测试时使用的是高端手机，这些设备拥有强大的 CPU 和 GPU，能够强行消化 Go 后端带来的密集数据轰炸，因此在开发阶段掩盖了问题。</p>
<p>而真实用户大量使用的中低端 Android 手机，其 GPU Headroom（GPU 动态余量）非常有限。当短时间内爆发大量布局计算（Layout Calculation）和视图绘制指令时，硬件性能瞬间见顶，直接导致掉帧。这也解释了为什么电池消耗会剧增——CPU 长时间处于高负荷的瞬时峰值状态。</p>
<h2>解决方案——不走回头路</h2>
<p>面对这种局面，最糟糕的决策是在 Go 后端增加 time.Sleep() 来模拟旧系统的延迟。这不仅是技术的倒退，更是对计算资源的侮辱。</p>
<p>该团队最终采取了正确的工程化修复方案，主要集中在移动端架构重构和API 聚合。</p>
<h3>移动端的“防洪堤”：批处理与防抖</h3>
<p>修复的核心在于让前端能够优雅地处理高速数据流，而不是被其淹没。</p>
<ol>
<li>
<p>状态更新批处理：<br />
重构移动端代码，不再对每一个 API 响应立即执行 dispatch。而是将短时间内的多个状态变更合并为一次 Update。在 React 18+ 中，这种自动批处理（Automatic Batching）已经成为默认行为，但在旧版 Redux 中需要手动实现或引入中间件。</p>
</li>
<li>
<p>防抖渲染：<br />
设置一个微小的时间窗口（例如 16ms，即一帧的时间），在该窗口内到达的所有数据只触发一次视图更新。这确保了无论后端多快，前端的渲染频率都不会超过屏幕刷新率。</p>
</li>
<li>
<p>引入 RTK Query：<br />
在评论区的讨论中，作者提到他们最终切换到了 Redux Toolkit Query。现代的状态管理库通常内置了去重（Deduplication）和缓存策略，能够更好地处理并发请求，避免不必要的渲染抖动。</p>
</li>
</ol>
<h3>后端适配：BFF 模式的回归</h3>
<p>既然 Go 处理并发和负载的能力如此之强，后端也承担了一部分优化工作。</p>
<ul>
<li>
<p>API 聚合（Aggregation）：<br />
团队合并了一些不必要分离的端点。以前为了解耦，可能会设计 GET /user, GET /settings, GET /feed。现在，既然 Go 处理 JSON 序列化的速度极快，可以将这些数据合并为一个 GET /bootstrap 或类似的大负载接口。</p>
<p>对于 Go 来说，序列化 50KB 的 JSON 和序列化 5KB 的 JSON 并没有本质的性能鸿沟；但对于移动端来说，将 3 次网络请求 + 3 次渲染循环 减少为 1 次网络请求 + 1 次渲染循环，是质的飞跃。</p>
</li>
</ul>
<h3>视觉测试的重要性</h3>
<p>作者特别提到了一个关键点：<strong>Vision Testing Tool</strong>。</p>
<p>常规的单元测试或集成测试只能验证“数据是否正确”，无法验证“动画是否流畅”。他们通过在真实的中低端设备上运行视觉测试工具（如 Drizz Dev 等），捕捉到了肉眼在高端机上难以察觉的微小掉帧。这提醒我们，在涉及端侧性能时，真实设备测试（Real Device Testing）是不可或缺的环节。</p>
<h2>给架构师与开发者的建议</h2>
<p>这个“Go 重构引发前端崩溃”的案例，为整个行业提供了宝贵的经验教训。它提醒我们，微服务架构中的“性能”从来不是孤立的指标。</p>
<h3>性能是一种“破坏性变更”</h3>
<p>在进行大规模重构时，我们通常只关注功能兼容性（API 字段是否一致）。但时序特性的剧烈变化，同样属于 API 契约的一部分。如果你的新系统比旧系统快 10 倍或慢 10 倍，它都可能破坏上下游的隐式依赖。</p>
<h3>全链路视角的必要性</h3>
<p>后端开发者的视野不能止步于 JSON 返回的那一刻。你需要了解你的消费者是谁，他们如何处理数据。</p>
<ul>
<li>如果是浏览器，它有强大的 V8 引擎和充足的内存。</li>
<li>如果是移动端，它受限于电池、散热和不稳定的网络。</li>
<li>如果是 IoT 设备，它可能只有几 KB 的内存。</li>
</ul>
<p>架构设计必须具备全链路视角（Full-stack Perspective）。</p>
<h3>避免“真空中的基准测试”</h3>
<p>作者提到，CTO 看到 benchmarks 后非常兴奋并全公司通报。这是一种典型的“真空指标”。真正的成功指标不应该是“API 响应时间”，而应该是“用户可见的交互延迟”或“页面完成加载时间”。</p>
<h3>拥抱 Go，但要理解 Go</h3>
<p>Go 语言的极致性能是双刃剑。它暴露了系统其他部分的低效。在这个案例中，Go 实际上充当了“压力测试工具”，它无情地暴露了前端架构中遗留的低效状态管理逻辑。</p>
<p>迁移到 Go 是正确的，它迫使团队偿还了前端的技术债务，最终不仅后端快，前端也更健壮了。</p>
<h2>小结</h2>
<p>“我们的 Go 微服务比旧的 Python 服务快 10 倍，但我们的 App 变差了。”</p>
<p>这句话初听是笑话，细品是哲学。它揭示了分布式系统的复杂性：<strong>局部最优不等于全局最优</strong>。</p>
<p>作为 Gopher，我们为 Go 语言的强悍性能感到自豪。但作为工程师，我们更应心存敬畏。在追求速度的道路上，不仅要跑得快，还要确保坐在副驾驶的“前端兄弟”没有被甩出车外。只有当端到端的用户体验得到提升时，重构才算真正成功。</p>
<p>资料链接：https://www.reddit.com/r/golang/comments/1r2n5ji/our_go_microservice_was_10x_faster_than_the_old/</p>
<hr />
<p><strong>你遇到过“太快”带来的烦恼吗？</strong></p>
<p>局部最优往往会导致全局崩溃。在你的开发生涯中，是否也遇到过这种“优化反而变差”的尴尬？你是如何处理前后端之间的“步调不一致”的？</p>
<p>欢迎在评论区分享你的“神反转”经历！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/02/13/go-microservices-refactoring-10x-backend-vs-mobile-collapse/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>我用 Go 重写了 Python 网关，性能提升 10 倍，却成了职场噩梦</title>
		<link>https://tonybai.com/2026/02/01/go-rewrite-python-gateway-10x-performance-career-nightmare/</link>
		<comments>https://tonybai.com/2026/02/01/go-rewrite-python-gateway-10x-performance-career-nightmare/#comments</comments>
		<pubDate>Sat, 31 Jan 2026 22:39:44 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[APIGateway]]></category>
		<category><![CDATA[API网关]]></category>
		<category><![CDATA[BusFactor]]></category>
		<category><![CDATA[BusinessValue]]></category>
		<category><![CDATA[CareerNightmare]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[MaintenanceCost]]></category>
		<category><![CDATA[MemoryUsage]]></category>
		<category><![CDATA[OpportunityCost]]></category>
		<category><![CDATA[PainPoints]]></category>
		<category><![CDATA[PerformanceBoost]]></category>
		<category><![CDATA[ProgressiveIntroduction]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[ResponseTime]]></category>
		<category><![CDATA[resumedrivendevelopment]]></category>
		<category><![CDATA[Rewrite]]></category>
		<category><![CDATA[SinglePointofFailure]]></category>
		<category><![CDATA[TeamCollaboration]]></category>
		<category><![CDATA[TechnicalDecision]]></category>
		<category><![CDATA[TechStack]]></category>
		<category><![CDATA[Throughput]]></category>
		<category><![CDATA[内存占用]]></category>
		<category><![CDATA[单点故障]]></category>
		<category><![CDATA[吞吐量]]></category>
		<category><![CDATA[响应时间]]></category>
		<category><![CDATA[商业价值]]></category>
		<category><![CDATA[团队协作]]></category>
		<category><![CDATA[巴士系数]]></category>
		<category><![CDATA[性能提升]]></category>
		<category><![CDATA[技术决策]]></category>
		<category><![CDATA[技术栈]]></category>
		<category><![CDATA[机会成本]]></category>
		<category><![CDATA[渐进式引入]]></category>
		<category><![CDATA[痛点]]></category>
		<category><![CDATA[简历驱动开发]]></category>
		<category><![CDATA[维护成本]]></category>
		<category><![CDATA[职场噩梦]]></category>
		<category><![CDATA[重写]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=5805</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/02/01/go-rewrite-python-gateway-10x-performance-career-nightmare 大家好，我是Tony Bai。 “如果你没有坏，就不要修它。” (If it ain&#8217;t broke, don&#8217;t fix it.) 这句老生常谈的工程谚语，最近在 r/golang 社区的一次热议中再次得到了血淋淋的验证。 一位开发者 分享了他即使成功将一个 Python 服务重写为 Go，并取得了显著的性能提升，却依然感到挫败和后悔的经历。 你可以将其看成是一个关于 Go vs Python 的技术故事，但在我眼中这更像是一堂关于技术决策、团队协作和职场生存的必修课。 故事：一场“完美”的技术胜利 故事的开端听起来像是一个典型的技术爽文。 作者说服了管理层，让他将现有的 API 网关从 Python/Flask 重写为 Go。理由非常充分且“正确”：性能和并发。 经过两个月的努力，重写非常成功： 吞吐量提升 10 倍。 内存占用减少到原来的 1/3。 部署时间从分钟级缩短到秒级。 从技术指标上看，这是一场完胜。Go 语言在这个场景下再次证明了其在云原生和高并发领域的统治力。 反转：一场“无感”的商业失败 然而，当新系统上线后，现实给了作者一记重拳。 用户感知到了什么？ Absolutely nothing.（完全没有。） 响应时间从 45ms 降到了 38ms。这 7ms 的提升，除了作者盯着 Grafana [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/go-rewrite-python-gateway-10x-performance-career-nightmare-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/02/01/go-rewrite-python-gateway-10x-performance-career-nightmare">本文永久链接</a> &#8211; https://tonybai.com/2026/02/01/go-rewrite-python-gateway-10x-performance-career-nightmare</p>
<p>大家好，我是Tony Bai。</p>
<p>“如果你没有坏，就不要修它。” (If it ain&#8217;t broke, don&#8217;t fix it.)</p>
<p>这句老生常谈的工程谚语，最近在 <a href="https://www.reddit.com/r/golang/comments/1qr9375/rewrote_our_python_api_gateway_in_go_and_now_its/">r/golang 社区的一次热议</a>中再次得到了血淋淋的验证。</p>
<p>一位开发者 分享了他即使成功将一个 Python 服务重写为 Go，并取得了显著的性能提升，却依然感到挫败和后悔的经历。</p>
<p>你可以将其看成是一个关于 Go vs Python 的技术故事，但在我眼中这更像是一堂关于技术决策、团队协作和职场生存的必修课。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/distributed-system-guide-qr.png" alt="" /></p>
<h2>故事：一场“完美”的技术胜利</h2>
<p>故事的开端听起来像是一个典型的技术爽文。</p>
<p>作者说服了管理层，让他将现有的 API 网关从 Python/Flask 重写为 Go。理由非常充分且“正确”：<strong>性能和并发</strong>。</p>
<p>经过两个月的努力，重写非常成功：</p>
<ul>
<li><strong>吞吐量提升 10 倍</strong>。</li>
<li><strong>内存占用减少到原来的 1/3</strong>。</li>
<li><strong>部署时间从分钟级缩短到秒级</strong>。</li>
</ul>
<p>从技术指标上看，这是一场完胜。Go 语言在这个场景下再次证明了其在云原生和高并发领域的统治力。</p>
<h2>反转：一场“无感”的商业失败</h2>
<p>然而，当新系统上线后，现实给了作者一记重拳。</p>
<p><strong>用户感知到了什么？</strong><br />
<strong>Absolutely nothing.（完全没有。）</strong></p>
<p>响应时间从 45ms 降到了 38ms。这 7ms 的提升，除了作者盯着 Grafana 监控面板自我陶醉外，没有任何用户能察觉到区别。</p>
<p><strong>团队感知到了什么？</strong></p>
<p><strong>巨大的风险和负担。</strong></p>
<p>原来的 Python 版本虽然性能稍逊，但完全能扛住现有的负载，而且团队所有人都知道如何维护它。现在，系统变成了一个只有作者一人能懂的 Go 服务。</p>
<p>结果就是：作者成为了唯一的维护者（Single Point of Failure），任何报警都只能找他，哪怕是在半夜或周末。</p>
<h2>社区的“毒舌”与洞见</h2>
<p>这篇帖子引发了数百条评论，虽然有些评论非常“毒舌”，但其中蕴含的工程智慧却发人深省。</p>
<h3>技术正确 ≠ 商业价值</h3>
<p>正如一位开发者指出的：“你花了公司两个月的薪水和机会成本，解决了一个并不存在的问题。”</p>
<p>在商业环境中，技术是手段，不是目的。如果性能提升不能转化为用户体验的改善（如更流畅的交互）或成本的显著降低（如服务器费用减半），那么这种优化就是没有商业价值的。</p>
<h3>“简历驱动开发” (Resume-Driven Development)</h3>
<p>不少人犀利地指出，这种重构往往是出自开发者的私心——为了学习新技术、为了给简历镀金。</p>
<blockquote>
<p>“这就是为什么我不想让程序员做商业决策。他们会为了微秒级的性能提升，制造出一系列未来的维护挑战。”</p>
</blockquote>
<h3>团队同质性的重要性</h3>
<p>在一个 Python 团队中引入 Go，打破了技术栈的同质性。这不仅增加了维护成本，还降低了团队的“巴士系数”（Bus Factor）。</p>
<blockquote>
<p>“有时候，最好的技术选择，就是你团队已经掌握的那一个。”</p>
<p>注：巴士系数（Bus Factor）是一个用于衡量团队或项目中关键人员的依赖程度的指标。它的核心概念是，如果某些关键成员（例如开发人员、设计师或管理人员）因意外（如被公交车撞到）而无法继续工作，项目仍能以多大程度上保持运作。</p>
</blockquote>
<h2>Go 的正确打开方式</h2>
<p>那么，这是否意味着我们在 Python/Java/Node 团队中就不能引入 Go 了？当然不是。但需要满足特定的前提：</p>
<ol>
<li><strong>痛点必须足够痛</strong>：现有的技术栈确实无法支撑业务发展（如严重的性能瓶颈、不可接受的延迟）。</li>
<li><strong>团队共识</strong>：重写不应该是个人的“独角戏”，而必须是团队的战略决策。至少要有 2-3 人愿意学习并维护新语言。</li>
<li><strong>渐进式引入</strong>：不要一上来就重写核心网关，可以从边缘服务或工具链开始，逐步培养团队的 Go 技能。</li>
</ol>
<h2>小结：成熟工程师的标志</h2>
<p>这个故事告诉我们，成为一名 Senior 工程师，不仅仅意味着写出更快的代码，更意味着懂得<strong>何时不写代码</strong>。</p>
<p>Go 是一把锋利的“屠龙刀”，但如果你的面前并没有龙，用它来切菜，可能不仅切不好，还会伤到自己。</p>
<p>下次当你想要重写一个服务时，请先问自己三个问题：</p>
<ol>
<li>它真的坏了吗？</li>
<li>这能为公司省钱或赚钱吗？</li>
<li>如果我离职了，谁来维护它？</li>
</ol>
<p>如果答案不确定，或许最好的选择是——<strong>Don&#8217;t fix what&#8217;s not broke.</strong></p>
<p>资料链接：https://www.reddit.com/r/golang/comments/1qr9375/rewrote_our_python_api_gateway_in_go_and_now_its/</p>
<hr />
<p><strong>你的“重构”悔恨录</strong></p>
<p>“重写”是每个程序员都曾有过的冲动。在你的职业生涯中，是否也曾因为执着于某种“新技术”或“极致性能”，而给团队带来了意想不到的麻烦？或者，你见过哪些典型的“简历驱动开发”案例？</p>
<p>欢迎在评论区分享你的故事！让我们在别人的教训中，学会做更成熟的决策。</p>
<p>如果这篇文章让你停下来思考了 30 秒，别忘了点个【赞】和【在看】，并转发给那个正准备“大干一场”的同事！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/02/01/go-rewrite-python-gateway-10x-performance-career-nightmare/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
