<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Chen Shungen</title><link>https://chenshungen.cn/</link><description>Recent content on Chen Shungen</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Mon, 20 Apr 2026 14:27:00 +0800</lastBuildDate><atom:link href="https://chenshungen.cn/index.xml" rel="self" type="application/rss+xml"/><item><title>塞尔达传说：旷野之息</title><link>https://chenshungen.cn/projects/zelda-botw/</link><pubDate>Thu, 16 Apr 2026 00:00:00 +0000</pubDate><guid>https://chenshungen.cn/projects/zelda-botw/</guid><description>&lt;p>开放世界冒险的巅峰之作。在广袤的海拉鲁大陆上自由探索，攀爬、滑翔、战斗，用你的方式书写属于自己的传说。&lt;/p></description></item><item><title>超级马力欧 奥德赛</title><link>https://chenshungen.cn/projects/mario-odyssey/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><guid>https://chenshungen.cn/projects/mario-odyssey/</guid><description>&lt;p>马力欧的环球冒险之旅。抛出帽子附身万物，在沙漠、都市、海洋等奇妙国度中收集力量之月，拯救碧姬公主。&lt;/p></description></item><item><title>Go 扩展并发原语与分布式并发</title><link>https://chenshungen.cn/blog/golang-concurrency/golang-extended-concurrency/</link><pubDate>Mon, 20 Apr 2026 14:27:00 +0800</pubDate><guid>https://chenshungen.cn/blog/golang-concurrency/golang-extended-concurrency/</guid><description>&lt;p>前面几篇我们讲了标准库的并发原语、atomic 和 Channel，掌握这些已经能解决 80% 的并发问题。但要进一步提升并发编程能力，还需要了解 &lt;strong>扩展并发原语&lt;/strong> 和 &lt;strong>分布式并发原语&lt;/strong>。这篇文章分两部分：上半部分讲 Go 官方和社区提供的进程内扩展原语（Semaphore、SingleFlight、ErrGroup、CyclicBarrier），下半部分讲基于 etcd 的分布式并发原语（Leader 选举、分布式锁、队列、栅栏、STM）。&lt;/p>
&lt;hr>
&lt;h1 id="上篇扩展并发原语">上篇：扩展并发原语&lt;/h1>
&lt;h2 id="一semaphore信号量">一、Semaphore（信号量）&lt;/h2>
&lt;h3 id="什么是信号量">什么是信号量？&lt;/h3>
&lt;p>信号量（Semaphore）是荷兰计算机科学家 Edsger Dijkstra 在 1963 年提出的并发原语，用来 &lt;strong>控制多个 goroutine 同时访问多个资源&lt;/strong>。&lt;/p>
&lt;p>它的核心是一个计数器（0 到 n），表示当前可用的资源数量：&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">┌────────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 信号量模型 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├────────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 初始资源数 = n │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Acquire (P 操作)：计数器 - 1 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 计数器 &amp;gt; 0 → 成功获取，继续执行 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 计数器 = 0 → 阻塞等待，直到有资源释放 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Release (V 操作)：计数器 + 1 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 唤醒一个等待中的 goroutine │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└────────────────────────────────────────────────────────────────┘&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;blockquote>
&lt;p>&lt;strong>P/V 操作&lt;/strong> 的名称来自荷兰语：P（Proberen，尝试）减少信号量，V（Verhogen，增加）增加信号量。&lt;/p></description></item><item><title>Go 内存模型</title><link>https://chenshungen.cn/blog/golang-concurrency/golang-memory-model/</link><pubDate>Mon, 20 Apr 2026 14:25:00 +0800</pubDate><guid>https://chenshungen.cn/blog/golang-concurrency/golang-memory-model/</guid><description>&lt;p>前面的文章我们讲了 Mutex、Channel、atomic 等各种并发工具，但有一个更底层的问题我们还没回答——&lt;strong>一个 goroutine 写入的值，另一个 goroutine 什么时候能看到？&lt;/strong> 这就是 Go 内存模型（The Go Memory Model）要回答的问题。&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>注意&lt;/strong>：这里的&amp;quot;内存模型&amp;quot;不是内存分配/回收，而是 &lt;strong>并发环境下变量的可见性规则&lt;/strong>。&lt;/p>&lt;/blockquote>
&lt;h2 id="一为什么需要内存模型">一、为什么需要内存模型？&lt;/h2>
&lt;p>直觉上，代码应该按你写的顺序执行。但现实中有两个因素会打破这种直觉：&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">┌──────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 打破执行顺序的两个因素 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├──────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 1. 编译器重排 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 编译器为了优化性能，可能调整指令执行顺序 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 只要在单 goroutine 内语义不变，就允许重排 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 2. CPU 多级缓存 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 每个 CPU 核有自己的 L1/L2 缓存 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 一个核写入的值不一定立即对其他核可见 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└──────────────────────────────────────────────────────────────┘&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;p>看一个例子：&lt;/p></description></item><item><title>Go 并发原语 - Channel</title><link>https://chenshungen.cn/blog/golang-concurrency/golang-channel/</link><pubDate>Mon, 20 Apr 2026 14:00:00 +0800</pubDate><guid>https://chenshungen.cn/blog/golang-concurrency/golang-channel/</guid><description>&lt;p>Channel 是 Go 语言内建的 &lt;strong>first-class 类型&lt;/strong>，也是 Go 与众不同的特性之一。它不是通过库提供的——而是直接内置在语言规范中，地位之高在编程语言中比较罕见。Channel 的设计源自 CSP（Communicating Sequential Process）模型：&lt;strong>不要通过共享内存来通信，要通过通信来共享内存。&lt;/strong>&lt;/p>
&lt;h2 id="一channel-基本用法">一、Channel 基本用法&lt;/h2>
&lt;h3 id="声明和初始化">声明和初始化&lt;/h3>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 声明&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">ch&lt;/span> &lt;span class="kd">chan&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="c1">// 双向 channel&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">sendCh&lt;/span> &lt;span class="kd">chan&lt;/span>&lt;span class="o">&amp;lt;-&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="c1">// 只发送&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">var&lt;/span> &lt;span class="nx">recvCh&lt;/span> &lt;span class="o">&amp;lt;-&lt;/span>&lt;span class="kd">chan&lt;/span> &lt;span class="kt">int&lt;/span> &lt;span class="c1">// 只接收&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// 初始化（必须用 make）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">ch&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">make&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">chan&lt;/span> &lt;span class="kt">int&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// 无缓冲&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">ch&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">make&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">chan&lt;/span> &lt;span class="kt">int&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="mi">10&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// 有缓冲，容量 10&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;h3 id="三种操作">三种操作&lt;/h3>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">┌──────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Channel 的三种操作 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├──────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ch &amp;lt;- value 发送：把 value 放入 channel │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ value := &amp;lt;-ch 接收：从 channel 取出值 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ close(ch) 关闭：关闭 channel │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└──────────────────────────────────────────────────────────────┘&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;h3 id="无缓冲-vs-有缓冲">无缓冲 vs 有缓冲&lt;/h3>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">无缓冲 channel (make(chan int))：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> 发送者 channel 接收者
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │── send ────→ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ (阻塞...) │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ ←── recv ────────│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ (解除阻塞) ──→│──→ (收到值) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> 发送和接收必须同时就绪，类似&amp;#34;面对面交接&amp;#34;。
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">有缓冲 channel (make(chan int, 3))：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> 发送者 buffer [_ _ _] 接收者
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │── send ────→ [v _ _] (不阻塞) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │── send ────→ [v v _] (不阻塞) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │── send ────→ [v v v] (不阻塞) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │── send ────→ [v v v] (阻塞! 满了) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ ←── recv ────────│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ (解除阻塞) ──→│──→ (取出一个值) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> 缓冲未满时发送不阻塞，缓冲为空时接收阻塞。&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;h2 id="二channel-的行为表">二、Channel 的行为表&lt;/h2>
&lt;p>对 channel 执行不同操作，在不同状态下的行为：&lt;/p></description></item><item><title>Go 并发原语 - atomic</title><link>https://chenshungen.cn/blog/golang-concurrency/golang-atomic/</link><pubDate>Mon, 20 Apr 2026 13:30:00 +0800</pubDate><guid>https://chenshungen.cn/blog/golang-concurrency/golang-atomic/</guid><description>&lt;p>前面讲 Mutex、WaitGroup 等并发原语的实现时，你会发现它们的底层都依赖 &lt;code>sync/atomic&lt;/code> 包的原子操作。原子操作是并发编程的最底层基石——比锁更轻量、比 Channel 更快，适合特定场景下的高性能并发控制。这一篇我们专门来讲 atomic。&lt;/p>
&lt;h2 id="一什么是原子操作">一、什么是原子操作？&lt;/h2>
&lt;p>原子操作是指 &lt;strong>不会被中断的操作&lt;/strong>。在其他 goroutine 看来，原子操作要么已经完成，要么还没开始，不会看到&amp;quot;执行了一半&amp;quot;的中间状态。&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">普通操作（count++，三步）： 原子操作（atomic.AddInt64，一步）：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> goroutine A goroutine B goroutine A goroutine B
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ 读取 count=5 │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ 读取 count=5 │ AddInt64(+1) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ count=5+1=6 │ │ (不可分割) │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ 写回 count=6 │ count=5+1=6 │ │ AddInt64(+1)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ 写回 count=6 │ │ (不可分割)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │ │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> 结果：6（丢失一次+1）💀 结果：7（正确）✅&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;p>原子操作为什么能保证这一点？因为 CPU 硬件直接支持：&lt;/p></description></item><item><title>Go 并发原语 - Context</title><link>https://chenshungen.cn/blog/golang-concurrency/golang-context/</link><pubDate>Mon, 20 Apr 2026 13:00:00 +0800</pubDate><guid>https://chenshungen.cn/blog/golang-concurrency/golang-context/</guid><description>&lt;p>并发编程中，除了&amp;quot;互斥访问&amp;quot;和&amp;quot;等待通知&amp;quot;之外，还有一类核心需求——&lt;strong>取消和超时控制&lt;/strong>。比如：HTTP 请求超时了，下游所有 goroutine 都应该停止工作；用户取消了操作，正在进行的数据库查询应该被中断。Go 标准库的 &lt;code>context&lt;/code> 包就是为了解决这类问题而生的。&lt;/p>
&lt;h2 id="一context-解决什么问题">一、Context 解决什么问题？&lt;/h2>
&lt;p>假设一个 HTTP 请求触发了多个 goroutine 并行处理：&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl"> HTTP 请求
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── goroutine: 查询数据库
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── goroutine: 调用下游 API
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── goroutine: 读取缓存&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;p>如果请求超时了（比如客户端断开连接），这三个 goroutine 应该如何知道&amp;quot;不用干了&amp;quot;？&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">没有 Context： 有 Context：
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> 请求超时 请求超时
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ 数据库查询还在跑... │── ctx.Done() 触发
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ 下游 API 还在等... │── 所有 goroutine 收到信号
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ 缓存读取还在等... │── 立即停止，释放资源
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── 资源浪费 💀 └── 干净退出 ✅&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;p>Context 提供了三个核心能力：&lt;/p></description></item><item><title>Go 并发原语 - Pool</title><link>https://chenshungen.cn/blog/golang-concurrency/golang-pool/</link><pubDate>Mon, 20 Apr 2026 12:30:00 +0800</pubDate><guid>https://chenshungen.cn/blog/golang-concurrency/golang-pool/</guid><description>&lt;p>Go 是自动垃圾回收的语言，创建对象没有回收的心理负担。但如果你要开发高性能应用，就必须关注 GC 的影响——大量创建堆上的对象，会增加 GC 标记的时间和 STW（stop-the-world）的开销。&lt;strong>对象池&lt;/strong> 是一种经典的优化手段：把不用的对象回收起来复用，减少堆分配和 GC 压力。Go 标准库提供了 &lt;code>sync.Pool&lt;/code> 来实现这个目的。&lt;/p>
&lt;p>这篇文章我们先讲 sync.Pool 的用法和原理，再扩展到连接池和 Worker Pool。&lt;/p>
&lt;h2 id="一syncpool-基本用法">一、sync.Pool 基本用法&lt;/h2>
&lt;p>sync.Pool 的 API 非常简洁：&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ sync.Pool │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├─────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ New func() any 创建新对象的工厂函数（Pool 为空时调用）│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Get() any 从池中取出一个对象 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ Put(x any) 把对象放回池中 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────┘&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;p>一个典型的用法——复用 &lt;code>bytes.Buffer&lt;/code>：&lt;/p></description></item><item><title>Go 并发原语 - Map</title><link>https://chenshungen.cn/blog/golang-concurrency/golang-map/</link><pubDate>Mon, 20 Apr 2026 12:00:00 +0800</pubDate><guid>https://chenshungen.cn/blog/golang-concurrency/golang-map/</guid><description>&lt;p>前面几篇我们聊了各种同步原语，这一篇聊一个更贴近日常开发的话题——&lt;strong>map 的并发安全&lt;/strong>。Go 内建的 map 类型不是线程安全的，并发读写会直接 panic。那怎么办？这一篇我们从内建 map 的基本用法和陷阱开始，逐步讲到加锁方案和标准库的 &lt;code>sync.Map&lt;/code>。&lt;/p>
&lt;h2 id="一内建-map-基本用法">一、内建 map 基本用法&lt;/h2>
&lt;p>Go 的 map 是内建的哈希表类型：&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="nx">m&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nb">make&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">map&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="kt">string&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="kt">int&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">m&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s">&amp;#34;age&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="mi">28&lt;/span> &lt;span class="c1">// 写入&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">v&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">m&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s">&amp;#34;age&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1">// 读取&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">v&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">ok&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">m&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="s">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="c1">// 读取 + 检查是否存在&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nb">delete&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">m&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;age&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// 删除&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;p>key 的类型必须是 &lt;strong>可比较的（comparable）&lt;/strong>——能用 &lt;code>==&lt;/code> 和 &lt;code>!=&lt;/code> 比较：&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">┌──────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ✅ 可以做 key 的类型 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├──────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ bool、整数、浮点数、复数、字符串 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 指针、Channel、接口 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 所有字段都可比较的 struct │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 元素都可比较的数组 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├──────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ❌ 不能做 key 的类型 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├──────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ slice、map、函数 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└──────────────────────────────────────────────────────────┘&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;h3 id="struct-做-key-的坑">struct 做 key 的坑&lt;/h3>
&lt;p>用 struct 做 key 时要特别小心——修改了 struct 字段后，就再也找不到原来的值了：&lt;/p></description></item><item><title>Go 并发原语 - Once</title><link>https://chenshungen.cn/blog/golang-concurrency/golang-once/</link><pubDate>Mon, 20 Apr 2026 11:30:00 +0800</pubDate><guid>https://chenshungen.cn/blog/golang-concurrency/golang-once/</guid><description>&lt;p>前面几篇我们聊了 Mutex、WaitGroup 和 Cond，它们各自解决不同维度的并发问题。这一篇聊一个相对简单但极其实用的原语——&lt;code>sync.Once&lt;/code>，它解决的是 &lt;strong>&amp;ldquo;确保某个操作只执行一次&amp;rdquo;&lt;/strong> 的问题，最经典的场景就是单例资源的延迟初始化。&lt;/p>
&lt;h2 id="一为什么需要-once">一、为什么需要 Once？&lt;/h2>
&lt;p>单例资源的初始化有好几种方式，按执行时机可以分成两类：&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 程序启动时初始化 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├─────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 1. package 级别变量 var startTime = time.Now() │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 2. init 函数 func init() { startTime = ... } │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 3. main 函数中调用 func main() { initApp() } │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ✅ 天然线程安全（Go 保证 init 串行执行） │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ❌ 无法延迟——程序启动就初始化，不管用不用得上 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────┘
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">┌─────────────────────────────────────────────────────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 首次使用时初始化（延迟初始化） │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├─────────────────────────────────────────────────────────────┤
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ 需要自己保证线程安全 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ✅ 按需初始化，不浪费资源 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ❌ 并发控制是个问题 │
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└─────────────────────────────────────────────────────────────┘&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;p>延迟初始化更灵活，但并发安全怎么办？最直接的想法是用 Mutex：&lt;/p></description></item><item><title>Go 并发原语 - Cond</title><link>https://chenshungen.cn/blog/golang-concurrency/golang-cond/</link><pubDate>Mon, 20 Apr 2026 11:00:00 +0800</pubDate><guid>https://chenshungen.cn/blog/golang-concurrency/golang-cond/</guid><description>&lt;p>前两篇我们聊了 Mutex 和 WaitGroup，它们分别解决&amp;quot;互斥访问&amp;quot;和&amp;quot;等待一组任务完成&amp;quot;的问题。但并发编程中还有一类需求——&lt;strong>等待某个条件满足后再继续执行&lt;/strong>。比如：队列满了，生产者要等；队列空了，消费者要等。这就是 &lt;code>sync.Cond&lt;/code>（条件变量）要解决的问题。&lt;/p>
&lt;h2 id="一为什么需要-cond">一、为什么需要 Cond？&lt;/h2>
&lt;p>假设你要实现一个限定容量的队列：队列满时生产者阻塞，队列空时消费者阻塞。没有 Cond 的话，你可能会这样写：&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ❌ 轮询方案：浪费 CPU，响应慢&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="nb">len&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">queue&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="nx">maxSize&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">time&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">10&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="nx">time&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Millisecond&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// 空转等待&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">queue&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="nb">append&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">queue&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">item&lt;/span>&lt;span class="p">)&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;p>这种轮询方式有两个严重问题：&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">问题 1：CPU 空转 问题 2：响应延迟
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> CPU 条件满足
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ──●──────────────┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │?│ │?│ │?│ │?│ │?│ ← 反复空问 │ 等待下一次轮询
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └─┘ └─┘ └─┘ └─┘ └─┘ ─────────────────●
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> 全是无效检查 最多延迟 10ms&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;p>&lt;strong>Cond 的方案则是：条件不满足就阻塞休眠，条件满足后立即唤醒，零空转、零延迟。&lt;/strong>&lt;/p></description></item><item><title>Go 并发原语 - WaitGroup</title><link>https://chenshungen.cn/blog/golang-concurrency/golang-waitgroup/</link><pubDate>Mon, 20 Apr 2026 10:30:00 +0800</pubDate><guid>https://chenshungen.cn/blog/golang-concurrency/golang-waitgroup/</guid><description>&lt;p>上一篇我们聊了 Mutex，它解决的是&amp;quot;同一时刻只能有一个 goroutine 访问共享资源&amp;quot;的问题。但并发编程中还有另一类常见需求——&lt;strong>等待一组任务全部完成后再继续&lt;/strong>。这就是 &lt;code>sync.WaitGroup&lt;/code> 要解决的问题。&lt;/p>
&lt;h2 id="一为什么需要-waitgroup">一、为什么需要 WaitGroup？&lt;/h2>
&lt;p>假设你要并行执行三个子任务，全部完成后才能进入下一步。没有 WaitGroup 的话，你可能会这样写：&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ❌ 轮询方案：又慢又浪费 CPU&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nx">done1&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">done2&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">done3&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kc">false&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="kc">false&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">go&lt;/span> &lt;span class="kd">func&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="cm">/* 任务1 */&lt;/span> &lt;span class="nx">done1&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span> &lt;span class="p">}()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">go&lt;/span> &lt;span class="kd">func&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="cm">/* 任务2 */&lt;/span> &lt;span class="nx">done2&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span> &lt;span class="p">}()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">go&lt;/span> &lt;span class="kd">func&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="cm">/* 任务3 */&lt;/span> &lt;span class="nx">done3&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="kc">true&lt;/span> &lt;span class="p">}()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">for&lt;/span> &lt;span class="p">!&lt;/span>&lt;span class="nx">done1&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="p">!&lt;/span>&lt;span class="nx">done2&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="p">!&lt;/span>&lt;span class="nx">done3&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nx">time&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Sleep&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">100&lt;/span> &lt;span class="o">*&lt;/span> &lt;span class="nx">time&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Millisecond&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// 空转等待&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;p>这种轮询方式有两个问题：&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">问题 1：响应慢 问题 2：浪费 CPU
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> 任务完成 CPU
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ──●────────────┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐ ┌─┐
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │ 等待轮询 │?│ │?│ │?│ │?│ │?│ ← 反复空问
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ───────────────● └─┘ └─┘ └─┘ └─┘ └─┘
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> 最多延迟 100ms 全是无效检查&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;p>WaitGroup 的方案则是：任务没完成就阻塞，全部完成后立即唤醒，零延迟、零空转。&lt;/p></description></item><item><title>Go 并发原语 - Mutex</title><link>https://chenshungen.cn/blog/golang-concurrency/golang-mutex/</link><pubDate>Mon, 20 Apr 2026 10:00:00 +0800</pubDate><guid>https://chenshungen.cn/blog/golang-concurrency/golang-mutex/</guid><description>&lt;p>并发编程是 Go 的灵魂，而 &lt;strong>Mutex（互斥锁）&lt;/strong> 是并发控制的第一道防线。这篇文章带你从&amp;quot;为什么需要锁&amp;quot;开始，一路走到 Mutex 的演进原理、常见坑点和读写锁 RWMutex，争取一文把 Mutex 讲透。&lt;/p>
&lt;h2 id="一没有锁的世界有多危险">一、没有锁的世界有多危险？&lt;/h2>
&lt;p>先看一个经典的并发计数器问题：&lt;/p>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="cl">&lt;span class="kn">package&lt;/span> &lt;span class="nx">main&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kn">import&lt;/span> &lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="s">&amp;#34;fmt&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="s">&amp;#34;sync&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">main&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="kd">var&lt;/span> &lt;span class="nx">count&lt;/span> &lt;span class="kt">int&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="kd">var&lt;/span> &lt;span class="nx">wg&lt;/span> &lt;span class="nx">sync&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">WaitGroup&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="k">for&lt;/span> &lt;span class="nx">i&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="mi">0&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nx">i&lt;/span> &lt;span class="p">&amp;lt;&lt;/span> &lt;span class="mi">10000&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="nx">i&lt;/span>&lt;span class="o">++&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">		&lt;span class="nx">wg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Add&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">1&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">		&lt;span class="k">go&lt;/span> &lt;span class="kd">func&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">			&lt;span class="k">defer&lt;/span> &lt;span class="nx">wg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Done&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">			&lt;span class="nx">count&lt;/span>&lt;span class="o">++&lt;/span> &lt;span class="c1">// 非原子操作：读取 → 加1 → 写回&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">		&lt;span class="p">}()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nx">wg&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Wait&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">	&lt;span class="nx">fmt&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Println&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;count:&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">count&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c1">// 几乎不可能是 10000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;p>多次运行，结果可能是 9831、9917、9756……每次都不一样。这就是典型的 &lt;strong>数据竞争（Data Race）&lt;/strong>。&lt;/p></description></item><item><title>游戏服务器开发实战笔记</title><link>https://chenshungen.cn/blog/game-server-erta/</link><pubDate>Sun, 19 Apr 2026 00:00:00 +0000</pubDate><guid>https://chenshungen.cn/blog/game-server-erta/</guid><description>&lt;p>这篇文章整合了我在游戏服务器开发过程中积累的几个核心主题的实践经验，时间跨度从 2018 到 2022 年。内容涵盖 3D 寻路、唯一 ID 生成、Go Plugin 热更新、通信安全加密，以及 Go 性能优化技巧。&lt;/p>
&lt;hr>
&lt;h2 id="一3d-寻路recastnavigation-在游戏服务器中的应用">一、3D 寻路：RecastNavigation 在游戏服务器中的应用&lt;/h2>
&lt;blockquote>
&lt;p>最初发表于 2018 年，记录了将 RecastNavigation 应用于游戏服务器的完整过程。&lt;/p>&lt;/blockquote>
&lt;h3 id="背景">背景&lt;/h3>
&lt;p>&lt;a href="https://github.com/recastnavigation/recastnavigation">RecastNavigation&lt;/a> 是一个开源的 Navigation-mesh Toolset for Games，核心功能包括 3D 寻路、控制 Agent 行走/移动、动态添加阻挡、动态改变地形。&lt;/p>
&lt;p>值得一提的是，RecastNavigation 其实就是 Unity3D 引擎自带的 Navigation 寻路模块的前身——这一点我曾在 Google Group 里和作者 memononen 确认过。&lt;/p>
&lt;h3 id="为什么要在服务器上做寻路">为什么要在服务器上做寻路&lt;/h3>
&lt;p>客户端做寻路很容易，现代游戏引擎都内置了这些工具。但在服务器上实现 3D 寻路，对于 AI 控制、反外挂验证等场景至关重要。RecastNavigation 用 C++ 实现，可以很方便地嵌入到 C++、Go、Python 等语言的服务器程序中。&lt;/p>
&lt;h3 id="从-unity-导出地图">从 Unity 导出地图&lt;/h3>
&lt;p>以 Unity 为客户端为例，有两种方式导出地图供 RecastNavigation 使用：&lt;/p>
&lt;p>&lt;strong>方式一：导出 Unity 已 bake 好的 NavMesh&lt;/strong>&lt;/p>
&lt;p>使用导出脚本将 Unity 中生成好的 NavMesh 导出为 obj 文件，然后放入 RecastNavigation 生成寻路网格。这种方式最直接，导出的 NavMesh 与 Unity 中一致。&lt;/p></description></item><item><title>我的开发者收藏夹：那些年攒下的技术链接</title><link>https://chenshungen.cn/blog/dev-bookmarks/</link><pubDate>Sat, 18 Apr 2026 00:00:00 +0000</pubDate><guid>https://chenshungen.cn/blog/dev-bookmarks/</guid><description>&lt;p>从 WordPress 迁移到 Hugo 的过程中，翻到了旧站上的「记事本」页面——一个从 2017 年就开始积攒的链接收藏夹。这些链接记录了我在不同阶段关注的技术方向，与其让它们躺在旧站里吃灰，不如整理出来，也算是一份个人技术成长的缩影。&lt;/p>
&lt;blockquote>
&lt;p>注意：部分链接年代久远，可能已经失效。&lt;/p>&lt;/blockquote>
&lt;h2 id="博客推荐">博客推荐&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://colobu.com/">鸟窝博客&lt;/a> — Go 语言领域非常活跃的中文博主&lt;/li>
&lt;li>&lt;a href="https://blog.codingnow.com/">云风的博客&lt;/a> — 游戏开发圈的前辈，写了二十多年博客&lt;/li>
&lt;/ul>
&lt;h2 id="go-语言">Go 语言&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.processon.com/view/link/5a9ba4c8e4b0a9d22eb3bdf0">Go 知识图谱&lt;/a> — 一张思维导图串起 Go 的核心知识点&lt;/li>
&lt;li>&lt;a href="https://go101.org/article/101.html">Go101&lt;/a> — 系统性地深入 Go 语言细节&lt;/li>
&lt;li>&lt;a href="https://go101.org/article/concurrent-common-mistakes.html">Go 并发常见错误&lt;/a> — 并发编程踩坑指南&lt;/li>
&lt;li>&lt;a href="https://bravenewgeek.com/so-you-wanna-go-fast/">So You Wanna Go Fast?&lt;/a> — Go 性能优化实战&lt;/li>
&lt;li>&lt;a href="https://github.com/gansidui/skiplist/blob/master/skiplist.go">Go SkipList 实现&lt;/a> — 跳表的 Go 实现参考&lt;/li>
&lt;li>&lt;a href="http://daizuozhuo.github.io/golang-rpc-practice/">go 标准库 rpc 实践&lt;/a> — net/rpc 使用指南&lt;/li>
&lt;li>&lt;a href="https://www.jianshu.com/p/cffe039fa060">Go-Kit&lt;/a> — Go 微服务框架入门&lt;/li>
&lt;li>&lt;a href="https://groups.google.com/g/golang-nuts/c/3FVAs9dPR8k/m/Jk9T3s7oIPEJ">map for readonly access will always remain thread-safe?&lt;/a> — golang-nuts 上关于 map 并发安全的经典讨论&lt;/li>
&lt;/ul>
&lt;h2 id="算法与数据结构">算法与数据结构&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.geeksforgeeks.org/top-algorithms-and-data-structures-for-competitive-programming/#algo1">经典算法&lt;/a> — GeeksforGeeks 竞赛编程算法合集&lt;/li>
&lt;li>&lt;a href="https://zhuanlan.zhihu.com/p/68409952">动态规划：最长公共子序列 + 最长公共子字符串&lt;/a> — DP 经典题目详解&lt;/li>
&lt;li>&lt;a href="https://blog.csdn.net/legend050709/article/details/114917637">限流之固定窗口/滑动窗口计数法&lt;/a> — 限流算法原理&lt;/li>
&lt;/ul>
&lt;h2 id="推荐书籍">推荐书籍&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://book.douban.com/subject/30329536/">《数据密集型应用系统设计》(DERTA)&lt;/a> — 分布式系统必读&lt;/li>
&lt;li>&lt;strong>《人月神话》&lt;/strong> — 软件工程经典，几十年过去了还是那么准&lt;/li>
&lt;/ul>
&lt;h2 id="kubernetes">Kubernetes&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.csdn.net/CHENYUFENG1991/article/details/79118446">单机 k8s 安装&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.cnblogs.com/zhenyuyaodidiao/p/6500830.html">k8s 集群部署 (CentOS 7)&lt;/a>&lt;/li>
&lt;li>&lt;a href="http://blog.51cto.com/jonauil/2086931">k8s Dashboard 部署 (一)&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.csdn.net/wh0426/article/details/54406555">k8s Dashboard 部署 (二)&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="c--c">C / C++&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://github.com/AnthonyCalandra/modern-cpp-features">Modern C++ Features (C++11/14/17)&lt;/a> — 新标准特性速查&lt;/li>
&lt;li>&lt;a href="https://gcc.gnu.org/projects/cxx-status.html">C++ Standards Support in GCC&lt;/a> — GCC 各版本对 C++ 标准的支持情况&lt;/li>
&lt;li>&lt;a href="http://www.cplusplus-soup.com/2010/01/freedelete-not-returning-memory-to-os.html">Free/Delete Not Returning Memory To OS?&lt;/a> — 内存释放后为什么系统看不到？&lt;/li>
&lt;li>&lt;a href="https://blog.joefom.com/archives/207">cc1.exe: sorry, unimplemented: 64-bit mode not compiled in&lt;/a> — MinGW 64 位编译报错解决&lt;/li>
&lt;/ul>
&lt;h2 id="数据库">数据库&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://bbs.redis.cn/forum.php?mod=viewthread&amp;amp;tid=728">Redis 应用分享&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://mongoing.com/archives/4368">MongoDB 分片集群 Chunk 分裂与迁移&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="工具与编辑器">工具与编辑器&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://regex101.com/r/zV2fO7/1">regex101&lt;/a> — 在线正则表达式测试，调正则必备&lt;/li>
&lt;li>&lt;a href="https://marketplace.visualstudio.com/items?itemName=vscodevim.vim">VSCode Vim 模式插件&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://stackoverflow.com/questions/17440659/capitalize-first-letter-of-each-word-in-a-selection-using-vim">Vim: Capitalize first letter of each word&lt;/a> — Vim 批量首字母大写技巧&lt;/li>
&lt;li>&lt;a href="https://templates.office.com/en-us/Resumes-and-Cover-Letters">简历模板&lt;/a> — Office 官方简历模板&lt;/li>
&lt;/ul>
&lt;h2 id="linux--运维">Linux / 运维&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="http://www.ocpsoft.org/tutorials/git/use-reflog-and-cherry-pick-to-restore-lost-commits/">git rebase 丢失 commit 找回&lt;/a> — reflog + cherry-pick 救命指南&lt;/li>
&lt;li>&lt;a href="https://love61v.github.io/2017/07/12/awk%E7%BB%9F%E8%AE%A1%E6%8E%92%E5%90%8D%E5%8D%95%E8%AF%8D%E5%87%BA%E7%8E%B0%E6%AC%A1%E6%95%B0/">linux awk 命令统计排名单词出现次数&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://www.cnblogs.com/lsdb/p/12010128.html">Linux 脚本只允许单实例运行&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="python">Python&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.devdungeon.com/content/working-binary-data-python">Working with Binary Data in Python&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>关于</title><link>https://chenshungen.cn/about/</link><pubDate>Thu, 16 Apr 2026 00:00:00 +0000</pubDate><guid>https://chenshungen.cn/about/</guid><description/></item><item><title>用 AI 重构我的个人网站：从 WordPress 到 Hugo</title><link>https://chenshungen.cn/blog/ai-native-website/</link><pubDate>Thu, 16 Apr 2026 00:00:00 +0000</pubDate><guid>https://chenshungen.cn/blog/ai-native-website/</guid><description>&lt;h2 id="为什么要告别-wordpress">为什么要告别 WordPress？&lt;/h2>
&lt;p>WordPress 是一个优秀的内容管理系统，但对于一个想要通过 AI 工具（如 Claude Code）来管理内容的开发者来说，它有几个痛点：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>内容存储在数据库中&lt;/strong>，AI 工具无法直接读写&lt;/li>
&lt;li>&lt;strong>PHP + MySQL 的技术栈&lt;/strong>维护成本高&lt;/li>
&lt;li>&lt;strong>安全更新&lt;/strong>需要频繁关注&lt;/li>
&lt;li>&lt;strong>动态渲染&lt;/strong>相比静态站点速度慢&lt;/li>
&lt;/ol>
&lt;h2 id="新方案hugo--adritian">新方案：Hugo + Adritian&lt;/h2>
&lt;p>最终选择了 Hugo 作为静态站点生成器，配合 Adritian 主题：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>内容即文件&lt;/strong>：所有文章都是 Markdown 文件，存储在 Git 仓库中&lt;/li>
&lt;li>&lt;strong>AI 友好&lt;/strong>：Claude Code 可以直接创建和编辑 &lt;code>.md&lt;/code> 文件&lt;/li>
&lt;li>&lt;strong>零维护&lt;/strong>：纯静态 HTML，没有数据库，没有后端&lt;/li>
&lt;li>&lt;strong>极速&lt;/strong>：毫秒级页面加载&lt;/li>
&lt;/ul>
&lt;h2 id="技术栈">技术栈&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>组件&lt;/th>
 &lt;th>选择&lt;/th>
 &lt;th>原因&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>静态生成器&lt;/td>
 &lt;td>Hugo&lt;/td>
 &lt;td>Go 构建，速度极快&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>主题&lt;/td>
 &lt;td>Adritian&lt;/td>
 &lt;td>专业网站风格，非纯博客&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>部署&lt;/td>
 &lt;td>阿里云 ECS&lt;/td>
 &lt;td>国内访问最快，已有备案&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>CI/CD&lt;/td>
 &lt;td>GitHub Actions&lt;/td>
 &lt;td>git push 自动构建部署&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="ai-内容发布流程">AI 内容发布流程&lt;/h2>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">Claude Code 写 Markdown → git push → GitHub Actions 构建 → 部署到 ECS&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;p>整个过程零人工干预，从写作到上线完全自动化。&lt;/p></description></item><item><title>Go 语言后端开发实践总结</title><link>https://chenshungen.cn/blog/golang-backend/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><guid>https://chenshungen.cn/blog/golang-backend/</guid><description>&lt;h2 id="为什么选择-go">为什么选择 Go？&lt;/h2>
&lt;p>Go 语言在后端开发中的优势不言而喻：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>编译速度快&lt;/strong>：秒级编译，开发体验流畅&lt;/li>
&lt;li>&lt;strong>并发原语优秀&lt;/strong>：goroutine + channel 模型简洁强大&lt;/li>
&lt;li>&lt;strong>部署简单&lt;/strong>：单二进制文件，无依赖&lt;/li>
&lt;li>&lt;strong>性能优异&lt;/strong>：接近 C 的性能，远超脚本语言&lt;/li>
&lt;/ul>
&lt;h2 id="项目结构推荐">项目结构推荐&lt;/h2>
&lt;div class="highlight-wrapper">
 &lt;button class="copy-code-btn" type="button" aria-label="Copy code to clipboard">
 &lt;svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
 &lt;rect x="9" y="9" width="13" height="13" rx="2" ry="2">&lt;/rect>
 &lt;path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1">&lt;/path>
 &lt;/svg>
 &lt;span class="copy-text">Copy&lt;/span>
 &lt;/button>&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">project/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── cmd/ # 应用入口
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── server/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── main.go
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── internal/ # 内部包（不对外暴露）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── handler/ # HTTP 处理器
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── service/ # 业务逻辑
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── repository/ # 数据访问
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── model/ # 数据模型
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── pkg/ # 可复用的公共包
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── api/ # API 定义（proto/openapi）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── config/ # 配置文件
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── deploy/ # 部署相关&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/div>
&lt;h2 id="错误处理模式">错误处理模式&lt;/h2>
&lt;p>Go 的错误处理虽然冗长，但有其设计哲学。推荐的做法：&lt;/p></description></item><item><title>分布式系统设计要点</title><link>https://chenshungen.cn/blog/distributed-systems/</link><pubDate>Tue, 14 Apr 2026 00:00:00 +0000</pubDate><guid>https://chenshungen.cn/blog/distributed-systems/</guid><description>&lt;h2 id="分布式系统的核心挑战">分布式系统的核心挑战&lt;/h2>
&lt;p>分布式系统面临的根本挑战可以用 CAP 定理来概括——一致性（Consistency）、可用性（Availability）、分区容错性（Partition Tolerance）三者不可兼得。&lt;/p>
&lt;p>在实际工程中，我们几乎总是需要保证分区容错性，因此核心的权衡在于：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>CP 系统&lt;/strong>：优先一致性，如 ZooKeeper、etcd&lt;/li>
&lt;li>&lt;strong>AP 系统&lt;/strong>：优先可用性，如 Cassandra、DynamoDB&lt;/li>
&lt;/ul>
&lt;h2 id="服务间通信">服务间通信&lt;/h2>
&lt;p>常见的服务间通信方式：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>方式&lt;/th>
 &lt;th>适用场景&lt;/th>
 &lt;th>优势&lt;/th>
 &lt;th>劣势&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>gRPC&lt;/td>
 &lt;td>内部服务调用&lt;/td>
 &lt;td>高性能、强类型&lt;/td>
 &lt;td>调试不如 REST 方便&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>REST&lt;/td>
 &lt;td>外部 API&lt;/td>
 &lt;td>通用、易理解&lt;/td>
 &lt;td>性能较低&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>消息队列&lt;/td>
 &lt;td>异步解耦&lt;/td>
 &lt;td>削峰、解耦&lt;/td>
 &lt;td>复杂度增加&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="关键设计原则">关键设计原则&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>幂等性&lt;/strong>：所有写操作都应该是幂等的&lt;/li>
&lt;li>&lt;strong>超时与重试&lt;/strong>：设置合理的超时，使用指数退避重试&lt;/li>
&lt;li>&lt;strong>熔断降级&lt;/strong>：防止级联故障&lt;/li>
&lt;li>&lt;strong>可观测性&lt;/strong>：日志、指标、链路追踪三者缺一不可&lt;/li>
&lt;/ol>
&lt;h2 id="总结">总结&lt;/h2>
&lt;p>分布式系统没有银弹。好的系统设计来自对业务场景的深入理解和对技术取舍的清晰认识。&lt;/p></description></item><item><title>Footer</title><link>https://chenshungen.cn/footer/footer/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://chenshungen.cn/footer/footer/</guid><description>&lt;section class="section section--border-bottom rad-animation-group section--padding">
 &lt;div class="container d-flex justify-content-center align-items-center">
 &lt;div class="row rad-fade-down">
 &lt;div class="col-12 text-center">
 
 
 &lt;div class="text-section__content">
 Powered by Hugo &amp;amp; Adritian | Managed by AI
 &lt;/div>
 &lt;/div>
 &lt;/div>
 &lt;/div>
&lt;/section></description></item><item><title>Home</title><link>https://chenshungen.cn/home/home/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://chenshungen.cn/home/home/</guid><description>&lt;section id="client-and-work-section" class="section section--border-bottom">
 &lt;div class="client-works-container">
 &lt;h2 class="rad-animation-group rad-fade-down">
 推荐游戏
 &lt;/h2>
 
 
 
 
 &lt;div class="row row--padded rad-animation-group rad-fade-down">
 
 &lt;div class="col-12">
 &lt;h3 style="margin-bottom: 0.5rem;">塞尔达传说：旷野之息&lt;/h3>
 &lt;div class="lead" style="margin-bottom: 1.5rem;">
 &lt;p>开放世界冒险的巅峰之作。在广袤的海拉鲁大陆上自由探索，攀爬、滑翔、战斗，用你的方式书写属于自己的传说。&lt;/p>

 &lt;/div>
 &lt;/div>
 
 &lt;div class="col-12 col-md-6" style="margin-bottom: 1rem;">
 &lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; border-radius: 8px;">
 
 
 
 
 &lt;picture>
 &lt;source srcset="https://chenshungen.cn/images/clients/zelda-botw_hu_e34ea61725b91756.webp" type="image/webp">
 &lt;img src="https://chenshungen.cn/images/clients/zelda-botw_hu_64a11149e2ba327d.webp"
 alt="塞尔达传说：旷野之息"
 loading="lazy"
 decoding="async"
 style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 8px;">
 &lt;/picture>
 
 &lt;/div>
 &lt;/div>
 
 
 &lt;div class="col-12 col-md-6" style="margin-bottom: 1rem;">
 &lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; border-radius: 8px;">
 &lt;iframe
 src="https://www.youtube.com/embed/zw47_q9wbBE"
 style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; border-radius: 8px;"
 allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
 allowfullscreen
 loading="lazy"
 title="Video"
 >&lt;/iframe>
 &lt;/div>
 &lt;/div>
 
 
 &lt;/div>
 
 
 
 &lt;div class="row row--padded rad-animation-group rad-fade-down">
 
 &lt;div class="col-12">
 &lt;h3 style="margin-bottom: 0.5rem;">超级马力欧 奥德赛&lt;/h3>
 &lt;div class="lead" style="margin-bottom: 1.5rem;">
 &lt;p>马力欧的环球冒险之旅。抛出帽子附身万物，在沙漠、都市、海洋等奇妙国度中收集力量之月，拯救碧姬公主。&lt;/p></description></item><item><title>搜索</title><link>https://chenshungen.cn/search/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://chenshungen.cn/search/</guid><description>搜索</description></item></channel></rss>