[{"content":"引言 快速排序（Quicksort）由 Tony Hoare 于 1959 年提出，是最经典的分治算法之一。其核心思想可以用一句话概括：\n选择一个 pivot，将数组划分为\u0026quot;小于 pivot\u0026quot;和\u0026quot;大于 pivot\u0026quot;两部分，然后递归处理子数组。\n这篇文章将从数学原理出发，结合 Python 实现，逐步深入工程中的优化技巧。\n数学基础：渐进复杂度分析 快速排序的时间复杂度依赖于划分是否均匀。设 $T(n)$ 为对长度为 $n$ 的数组排序的期望时间，则有递推式：\n$$ T(n) = \\frac{1}{n} \\sum_{k=0}^{n-1} \\big[T(k) + T(n-k-1)\\big] + \\Theta(n) $$\n解此递推式可得期望时间复杂度为 $\\Theta(n \\log n)$。我们可以用积分近似来验证：\n$$ \\int_{1}^{n} x \\ln x , dx \\approx \\frac{n^2 \\ln n}{2} - \\frac{n^2}{4} $$\n而最坏情况下，每次划分都极不均匀（例如已排序数组且总是选首元素为 pivot），退化至：\n$$ T(n) = T(n-1) + \\Theta(n) \\implies T(n) = \\Theta(n^2) $$\n空间复杂度 递归调用栈的深度在最好情况下为 $O(\\log n)$，最坏情况下为 $O(n)$。通过尾递归优化可以将最坏空间降至 $O(\\log n)$。\n算法实现 基础版本：Lomuto 划分 1def quicksort_lomuto(arr: list[int], low: int, high: int) -\u0026gt; None: 2 \u0026#34;\u0026#34;\u0026#34;Lomuto partition scheme — 简单直观但交换次数较多\u0026#34;\u0026#34;\u0026#34; 3 if low \u0026gt;= high: 4 return 5 6 pivot = arr[high] # 选最后一个元素作为 pivot 7 i = low - 1 # i 指向\u0026#34;小于 pivot 的区域\u0026#34;的末尾 8 9 for j in range(low, high): 10 if arr[j] \u0026lt; pivot: 11 i += 1 12 arr[i], arr[j] = arr[j], arr[i] 13 14 i += 1 15 arr[i], arr[high] = arr[high], arr[i] # 将 pivot 放到正确位置 16 17 quicksort_lomuto(arr, low, i - 1) 18 quicksort_lomuto(arr, i + 1, high) 在 Python 中，还可以用更简洁的列表推导式：\n1def quicksort_pythonic(arr: list[int]) -\u0026gt; list[int]: 2 \u0026#34;\u0026#34;\u0026#34;Functional-style quicksort — NOT in-place\u0026#34;\u0026#34;\u0026#34; 3 if len(arr) \u0026lt;= 1: 4 return arr 5 pivot = arr[len(arr) // 2] 6 left = [x for x in arr if x \u0026lt; pivot] 7 mid = [x for x in arr if x == pivot] 8 right = [x for x in arr if x \u0026gt; pivot] 9 return quicksort_pythonic(left) + mid + quicksort_pythonic(right) 工程优化版本：三路划分 + 插入排序混合 1// 三路划分 (Three-way Partition) —— 适合大量重复元素 2void quicksort_3way(int arr[], int low, int high) { 3 if (low \u0026gt;= high) return; 4 5 // 小数组切换到插入排序 6 if (high - low \u0026lt; 16) { 7 insertion_sort(arr + low, high - low + 1); 8 return; 9 } 10 11 int lt = low, gt = high; 12 int pivot = arr[low]; 13 int i = low; 14 15 while (i \u0026lt;= gt) { 16 if (arr[i] \u0026lt; pivot) swap(arr + lt++, arr + i++); 17 else if (arr[i] \u0026gt; pivot) swap(arr + i, arr + gt--); 18 else i++; 19 } 20 21 quicksort_3way(arr, low, lt - 1); 22 quicksort_3way(arr, gt + 1, high); 23} 不同划分策略对比 策略 pivot 选择 最坏时间 额外空间 重复元素处理 Lomuto 固定末尾 $O(n^2)$ $O(1)$ 差 Hoare 固定中间 $O(n^2)$ $O(1)$ 一般 三路划分 固定首元素 $O(n^2)$ $O(1)$ 优秀 IntroSort 三数取中 $O(n \\log n)$ $O(\\log n)$ 良好 PDQSort 多种启发式 $O(n \\log n)$ $O(\\log n)$ 极佳 备注：Rust 标准库的 slice::sort_unstable 使用 PDQSort（Pattern-Defeating Quicksort），它在检测到\u0026quot;过于有序\u0026quot;时会自动切换为堆排序。\n性能基准测试 使用 Go 的 testing 包对一百万条随机记录进行基准测试：\n1func BenchmarkQuicksort(b *testing.B) { 2 data := make([]int, 1_000_000) 3 for i := range data { 4 data[i] = rand.Intn(1_000_000) 5 } 6 b.ResetTimer() 7 for i := 0; i \u0026lt; b.N; i++ { 8 copy := append([]int(nil), data...) 9 quicksort(copy) 10 } 11} 12// BenchmarkQuicksort-16 4 286 ms/op 图：快速排序动画演示 (来源: Wikipedia)\n实际应用场景 下表总结了不同语言/库中快速排序的使用情况：\n语言 / 库 排序函数 底层算法 是否稳定 C++ std::sort std::sort Introsort ✗ Rust slice::sort_unstable PDQSort ✗ Python list.sort() Timsort (归并 + 插入) ✓ Java Arrays.sort (基本类型) Dual-Pivot Quicksort 双轴快排 ✗ Go sort.Slice PDQSort (≥1.21) ✗ JavaScript V8 Array.prototype.sort Timsort ✓ 小结 在这篇文章中，我们涵盖了：\n快速排序的递推式 $T(n)$ 及其数学分析 三种不同风格的代码实现：Lomuto、Pythonic、三路划分 C 不同 pivot 选择策略的性能对比 各主流语言标准库的排序算法选择 关键结论：快速排序仍是大多数标准库的首选通用排序，但几乎都加入了混合策略来避免最坏情况。\n本文共计约 2000 字，适合有一定算法基础的读者。如有疑问欢迎在评论区讨论。\n","permalink":"https://biribiribird.top/posts/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97%E4%BB%8E%E5%88%86%E6%B2%BB%E6%80%9D%E6%83%B3%E5%88%B0%E5%B7%A5%E7%A8%8B%E4%BC%98%E5%8C%96/","summary":"\u003ch2 id=\"引言\"\u003e引言\u003c/h2\u003e\n\u003cp\u003e快速排序（Quicksort）由 \u003cstrong\u003eTony Hoare\u003c/strong\u003e 于 1959 年提出，是最经典的分治算法之一。其核心思想可以用一句话概括：\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e选择一个 pivot，将数组划分为\u0026quot;小于 pivot\u0026quot;和\u0026quot;大于 pivot\u0026quot;两部分，然后递归处理子数组。\u003c/p\u003e","title":"快速排序完全指南：从分治思想到工程优化"},{"content":"前言 反向传播（Backpropagation）是训练神经网络的核心算法。本文将深入探讨其数学本质——多元函数链式法则的高效实现。\n计算图视角下的链式法则 考虑一个简单的三层网络：\n$$ \\begin{aligned} z_1 \u0026amp;= W_1 x + b_1 \\ a_1 \u0026amp;= \\sigma(z_1) \\ z_2 \u0026amp;= W_2 a_1 + b_2 \\ \\hat{y} \u0026amp;= \\text{softmax}(z_2) \\ \\mathcal{L} \u0026amp;= -\\sum_{k} y_k \\log \\hat{y}_k \\end{aligned} $$\n对应的计算图如下：\n标量反向传播 对于标量函数 $f(g(h(x)))$，链式法则给出：\n$$ \\frac{df}{dx} = \\frac{df}{dg} \\cdot \\frac{dg}{dh} \\cdot \\frac{dh}{dx} $$\n以 Sigmoid 激活函数为例，其导数的简洁形式是一个经典技巧点：\n1def sigmoid(x: float) -\u0026gt; float: 2 s = 1.0 / (1.0 + math.exp(-x)) 3 return s 4 5def sigmoid_backward(d_out: float, s: float) -\u0026gt; float: 6 # sigmoid 导数: sigma(x) * (1 - sigma(x)) 7 return d_out * s * (1.0 - s) 矩阵/张量反向传播 当推广到矩阵时，维度一致性是关键。对于矩阵乘法 $Y = XW$：\n$$ \\frac{\\partial \\mathcal{L}}{\\partial X} = \\frac{\\partial \\mathcal{L}}{\\partial Y} \\cdot W^T $$\n$$ \\frac{\\partial \\mathcal{L}}{\\partial W} = X^T \\cdot \\frac{\\partial \\mathcal{L}}{\\partial Y} $$\n这里的 · 表示矩阵乘法。在实际框架中，这些梯度由 autograd 引擎 自动计算。\nPyTorch 实战：自定义 Autograd Function 1import torch 2from torch.autograd import Function 3 4class MyLinear(Function): 5 \u0026#34;\u0026#34;\u0026#34;自定义线性层的前向与反向传播\u0026#34;\u0026#34;\u0026#34; 6 7 @staticmethod 8 def forward(ctx, input, weight, bias=None): 9 # 保存反向所需变量 10 ctx.save_for_backward(input, weight, bias) 11 output = input.mm(weight.t()) 12 if bias is not None: 13 output += bias.unsqueeze(0).expand_as(output) 14 return output 15 16 @staticmethod 17 def backward(ctx, grad_output): 18 input, weight, bias = ctx.saved_tensors 19 grad_input = grad_weight = grad_bias = None 20 21 # 根据链式法则计算各梯度 22 if ctx.needs_input_grad[0]: 23 grad_input = grad_output.mm(weight) # dL/dX = dL/dY · W 24 if ctx.needs_input_grad[1]: 25 grad_weight = grad_output.t().mm(input) # dL/dW = Y_grad^T · X 26 if bias is not None and ctx.needs_input_grad[2]: 27 grad_bias = grad_output.sum(0) # dL/db = sum(dL/dY, dim=0) 28 29 return grad_input, grad_weight, grad_bias 调试梯度时，数值梯度检查（torch.autograd.gradcheck）是必不可少的工具：\n1# 使用 gradcheck 验证自定义反向传播 2$ python -c \u0026#34; 3import torch 4from my_linear import MyLinear 5input = torch.randn(20, 10, dtype=torch.double, requires_grad=True) 6weight = torch.randn(5, 10, dtype=torch.double, requires_grad=True) 7torch.autograd.gradcheck(MyLinear.apply, (input, weight), eps=1e-6, atol=1e-4) 8print(\u0026#39;Gradient check passed!\u0026#39;) 9\u0026#34; 激活函数对比 激活函数 公式 导数值域 优点 缺点 Sigmoid $\\sigma(x) = \\frac{1}{1+e^{-x}}$ $(0, 0.25]$ 平滑、有界 梯度消失 Tanh $\\tanh(x) = \\frac{e^x-e^{-x}}{e^x+e^{-x}}$ $(0, 1]$ 零中心化 梯度消失 ReLU $f(x)=\\max(0,x)$ ${0, 1}$ 计算快、缓解梯度消失 Dead Neuron GELU $x \\cdot \\Phi(x)$ $\\approx (0, 1]$ 平滑、概率解释 计算略贵 SwiGLU $x \\cdot \\sigma(\\beta x)$ — LLM 标配 参数量翻倍 Why GELU? GELU（Gaussian Error Linear Unit）在 Transformer 架构中表现优异，因为它是 ReLU 的平滑近似——对每个输入应用一个由标准正态 CDF $\\Phi(x)$ 决定的\u0026quot;门控概率\u0026quot;。\n常见问题排查清单 在实践中，反向传播的调试常有以下痛点：\n梯度爆炸（Gradient Explosion）：损失突然变成 NaN 使用 torch.nn.utils.clip_grad_norm_ 进行梯度裁剪 检查学习率是否过大 梯度消失（Vanishing Gradient）：loss 几乎不下降 换用 ReLU / GELU 替代 Sigmoid 添加 BatchNorm / LayerNorm 形状不匹配（Shape Mismatch）：RuntimeError: shape '[64, 10]' is invalid for input of size 1280 仔细追踪 forward 中每一步的 tensor shape 善用 .view() / .reshape() / .flatten() 现代框架的计算图范式对比 框架 图构建方式 动态图 分布式策略 PyTorch Define-by-Run ✓ DDP / FSDP TensorFlow 2.x Eager + tf.function ✓ MirroredStrategy JAX 函数式 + grad()/vmap() ✓ pmap() / pjit Flux.jl (Julia) 原生 Julia 自动微分 ✓ — 总结 我们用一张表回顾核心概念：\n概念 符号 直觉理解 前向传播 $x \\mapsto f(x)$ 从输入计算输出 反向传播 $\\frac{\\partial \\mathcal{L}}{\\partial x}$ 回答\u0026quot;改变 $x$ 会如何影响最终损失？\u0026quot; 梯度累积 $\\sum \\nabla$ 用 micro-batch 模拟大 batch 链式法则 $\\frac{\\partial z}{\\partial x} = \\frac{\\partial z}{\\partial y} \\frac{\\partial y}{\\partial x}$ 将复杂梯度分解为简单梯度的乘积 反向传播的本质，就是把一个复杂函数的梯度计算分解为有向无环图上每个节点的局部雅可比乘积。掌握了这一点，也就掌握了所有现代深度学习框架的核心抽象。\n推荐阅读：《The Autodiff Cookbook》by JAX team\n","permalink":"https://biribiribird.top/posts/%E6%B7%B1%E5%BA%A6%E8%A7%A3%E6%9E%90%E5%8F%8D%E5%90%91%E4%BC%A0%E6%92%AD%E4%BB%8E%E6%A0%87%E9%87%8F%E5%88%B0%E5%BC%A0%E9%87%8F%E7%9A%84%E8%87%AA%E5%8A%A8%E5%BE%AE%E5%88%86/","summary":"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e反向传播（Backpropagation）是训练神经网络的核心算法。本文将深入探讨其数学本质——\u003cstrong\u003e多元函数链式法则\u003c/strong\u003e的高效实现。\u003c/p\u003e\n\u003ch2 id=\"计算图视角下的链式法则\"\u003e计算图视角下的链式法则\u003c/h2\u003e\n\u003cp\u003e考虑一个简单的三层网络：\u003c/p\u003e","title":"深度解析反向传播：从标量到张量的自动微分"},{"content":"开篇 Don\u0026rsquo;t communicate by sharing memory; share memory by communicating.\n— Effective Go\nGo 语言的并发哲学围绕一句名言展开：不要通过共享内存来通信，而要通过通信来共享内存。这篇文章将通过三个递进的实战示例，展示如何将 goroutine、channel 和 context.Context 组合成健壮的并发程序。\n基础组件速览 Goroutine Goroutine 是 Go 的轻量级用户态线程，由 Go 运行时（GMP 模型）调度。启动一个只需要 go 关键字：\n1package main 2 3import ( 4 \u0026#34;fmt\u0026#34; 5 \u0026#34;time\u0026#34; 6) 7 8func main() { 9 go func() { 10 fmt.Println(\u0026#34;Hello from goroutine!\u0026#34;) 11 }() 12 13 time.Sleep(10 * time.Millisecond) // 等待 goroutine 执行完毕 14} GMP 模型中，每个 P（Processor）绑定一个 M（Machine/OS thread），调度本地运行队列中的 G（Goroutine）。核心数据结构大致如下：\n1// runtime/runtime2.go (简化示意) 2type g struct { 3 stack stack // goroutine 栈 4 sched gobuf // 调度上下文 (sp, pc, bp...) 5 atomicstatus uint32 // _Gidle / _Grunning / _Gwaiting... 6} 7 8type p struct { 9 runq [256]guintptr // 本地运行队列 10 runnext guintptr // 下一个优先运行的 G 11 m muintptr // 当前绑定的 M 12} Channel Channel 是 goroutine 之间传递数据的类型安全管道。make(chan T, n) 创建缓冲区容量为 n 的 Channel。\n无缓冲 channel：ch := make(chan int) — 发送方阻塞直到接收方就绪（同步） 有缓冲 channel：ch := make(chan int, 10) — 缓冲区满之前不阻塞（异步） 1// Fan-in pattern: 多路输入合并为单路输出 2func fanIn(ch1, ch2 \u0026lt;-chan string) \u0026lt;-chan string { 3 out := make(chan string) 4 go func() { 5 for { 6 select { 7 case s := \u0026lt;-ch1: 8 out \u0026lt;- s 9 case s := \u0026lt;-ch2: 10 out \u0026lt;- s 11 } 12 } 13 }() 14 return out 15} 实战一：带超时控制的并发爬虫 结合 context.WithTimeout 和 sync.WaitGroup 实现可控的并发网络请求：\n1package crawler 2 3import ( 4 \u0026#34;context\u0026#34; 5 \u0026#34;fmt\u0026#34; 6 \u0026#34;net/http\u0026#34; 7 \u0026#34;sync\u0026#34; 8 \u0026#34;time\u0026#34; 9) 10 11type Result struct { 12 URL string 13 StatusCode int 14 Duration time.Duration 15 Err error 16} 17 18func Crawl(ctx context.Context, urls []string, concurrency int) []Result { 19 limiter := make(chan struct{}, concurrency) // 并发度控制 20 var wg sync.WaitGroup 21 results := make([]Result, 0, len(urls)) 22 var mu sync.Mutex 23 24 for _, u := range urls { 25 select { 26 case \u0026lt;-ctx.Done(): 27 break // 全局超时，不再启动新请求 28 default: 29 } 30 31 wg.Add(1) 32 go func(url string) { 33 defer wg.Done() 34 35 limiter \u0026lt;- struct{}{} // 获取令牌 36 defer func() { \u0026lt;-limiter }() // 释放令牌 37 38 start := time.Now() 39 resp, err := http.Get(url) 40 d := time.Since(start) 41 42 mu.Lock() 43 defer mu.Unlock() 44 45 r := Result{URL: url, Duration: d} 46 if err != nil { 47 r.Err = err 48 } else { 49 r.StatusCode = resp.StatusCode 50 resp.Body.Close() 51 } 52 results = append(results, r) 53 }(u) 54 } 55 56 wg.Wait() 57 return results 58} 实战二：Pipeline 模式 — 数据流的流水线处理 将处理流程拆分为多个 stage，每个 stage 由一组 goroutine 处理：\n1// Stage 1: 生成数字流 2func generator(ctx context.Context, nums ...int) \u0026lt;-chan int { 3 out := make(chan int) 4 go func() { 5 defer close(out) 6 for _, n := range nums { 7 select { 8 case out \u0026lt;- n: 9 case \u0026lt;-ctx.Done(): 10 return 11 } 12 } 13 }() 14 return out 15} 16 17// Stage 2: 平方运算 18func square(ctx context.Context, in \u0026lt;-chan int) \u0026lt;-chan int { 19 out := make(chan int) 20 go func() { 21 defer close(out) 22 for n := range in { 23 select { 24 case out \u0026lt;- n * n: 25 case \u0026lt;-ctx.Done(): 26 return 27 } 28 } 29 }() 30 return out 31} 32 33// Stage 3: 过滤结果 34func filter(ctx context.Context, in \u0026lt;-chan int, predicate func(int) bool) \u0026lt;-chan int { 35 out := make(chan int) 36 go func() { 37 defer close(out) 38 for n := range in { 39 if predicate(n) { 40 select { 41 case out \u0026lt;- n: 42 case \u0026lt;-ctx.Done(): 43 return 44 } 45 } 46 } 47 }() 48 return out 49} Pipeline 的优雅之处在于：当你取消 ctx 时，整个流水线会逐级关闭，不会留下泄漏的 goroutine。\n并发模型对比 模型 代表语言 调度方式 栈大小 通信机制 1:1 线程 C, Java (传统) OS 内核 ~8 MB 共享内存 + 锁 M:N 协程 Go 用户态 GMP ~2 KB (可增长) Channel async/await Rust, JS, Python 编译器状态机 零开销 Future/Promise Actor 模型 Erlang/Elixir BEAM VM ~2.5 KB 消息传递 Structured Concurrency Kotlin, Swift 语言级作用域 — 结构化作用域 性能数据 以下是在 8 核机器上对比不同并发模式的吞吐量：\n场景 模式 QPS P99 延迟 goroutine 数量 HTTP Proxy Goroutine-per-conn 45,000 12 ms ~200 数据聚合 Fan-in / Fan-out 120,000 3 ms ~80 日志写入 有缓冲 channel + 单 writer 480,000 0.5 ms 2 RPC 网关 Worker Pool (GOMAXPROCS) 85,000 8 ms ~32 常见陷阱与解法 1. Goroutine 泄漏 1// ❌ BAD: 如果 ctx 被取消，ch 永远不会被读取，goroutine 永久阻塞 2func bad(ctx context.Context) \u0026lt;-chan int { 3 ch := make(chan int) 4 go func() { 5 result := expensiveComputation() 6 ch \u0026lt;- result // ctx 取消后无人接收，goroutine 泄漏！ 7 }() 8 return ch 9} 10 11// ✓ GOOD: 使用 select 响应取消 12func good(ctx context.Context) \u0026lt;-chan int { 13 ch := make(chan int) 14 go func() { 15 result := expensiveComputation() 16 select { 17 case ch \u0026lt;- result: 18 case \u0026lt;-ctx.Done(): // 安全退出 19 return 20 } 21 }() 22 return ch 23} 2. 关闭已关闭的 Channel 1// panic: close of closed channel 2func safeClose() { 3 ch := make(chan int) 4 var once sync.Once 5 closeCh := func() { once.Do(func() { close(ch) }) } 6 7 go func() { closeCh() }() 8 go func() { closeCh() }() // 使用 sync.Once 保证只关一次 9} 3. for range 循环变量捕获 1// ❌ BAD (Go \u0026lt; 1.22): 循环变量在迭代间复用 2for _, v := range items { 3 go func() { 4 process(v) // v 被所有 goroutine 共享！ 5 }() 6} 7 8// ✓ GOOD: 将变量作为参数传入 9for _, v := range items { 10 go func(val Item) { 11 process(val) 12 }(v) 13} 14// 或 Go ≥ 1.22 中循环变量自动具有每次迭代独立的作用域 小结 通过本文，我们系统地梳理了 Go 并发的核心范式和常见模式：\n知识点 关键内容 并发原语 goroutine (轻量线程), channel (类型安全管道), sync 包 (WaitGroup/Mutex/Once) Context 传递 context.WithTimeout, context.WithCancel 构建可取消的调用链 Pipeline 多 stage \u0026lt;-chan 串联，取消信号沿流水线传播 Fan-in / Fan-out 多路扇入、多工作协程扇出，select 语句实现多路复用 常见陷阱 goroutine 泄漏、channel panic、循环变量捕获 Go 的并发模型将 CSP（Communicating Sequential Processes）的思想带入了主流工程实践——用 channel 连接 goroutine，就是并发版的 Unix 管道。\n延伸阅读：The Go Memory Model | Go Concurrency Patterns (2012)\n","permalink":"https://biribiribird.top/posts/go-%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B%E5%AE%9E%E6%88%98goroutinechannel-%E4%B8%8E-context-%E7%9A%84%E4%BC%98%E9%9B%85%E7%BB%84%E5%90%88/","summary":"\u003ch2 id=\"开篇\"\u003e开篇\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003eDon\u0026rsquo;t communicate by sharing memory; share memory by communicating.\u003c/p\u003e\n\u003cp\u003e— \u003cem\u003eEffective Go\u003c/em\u003e\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eGo 语言的并发哲学围绕一句名言展开：\u003cstrong\u003e不要通过共享内存来通信，而要通过通信来共享内存\u003c/strong\u003e。这篇文章将通过三个递进的实战示例，展示如何将 \u003ccode\u003egoroutine\u003c/code\u003e、\u003ccode\u003echannel\u003c/code\u003e 和 \u003ccode\u003econtext.Context\u003c/code\u003e 组合成健壮的并发程序。\u003c/p\u003e","title":"Go 并发编程实战：Goroutine、Channel 与 Context 的优雅组合"},{"content":"关于本站 这里是 BiribiriBird 的个人博客，主要记录编程、算法、系统设计方面的学习笔记。\n建站的初衷很简单：写作是最好的思考方式。把模糊的理解写成清晰的文字，过程中自然会暴露盲区、理清思路。如果能顺便帮到正在读的你，那就更好了。\n关于我 方向：后端 / 系统编程，关注性能与正确性 语言：Go、Python、Rust 兴趣：分布式系统、编程语言设计、开源硬件 联系 GitHub：aoijays 邮箱：biribiribird AT outlook.com 声明 本站所有文章以 CC BY 4.0 协议发布。转载请署名并附原文链接。文中观点仅代表个人，与技术社区和雇主无关。\n","permalink":"https://biribiribird.top/about/","summary":"\u003ch2 id=\"关于本站\"\u003e关于本站\u003c/h2\u003e\n\u003cp\u003e这里是 \u003cstrong\u003eBiribiriBird\u003c/strong\u003e 的个人博客，主要记录编程、算法、系统设计方面的学习笔记。\u003c/p\u003e\n\u003cp\u003e建站的初衷很简单：写作是最好的思考方式。把模糊的理解写成清晰的文字，过程中自然会暴露盲区、理清思路。如果能顺便帮到正在读的你，那就更好了。\u003c/p\u003e","title":"关于"},{"content":"常去的地方 站点 描述 Paul Graham Essays — 硅谷最会写文章的程序员 Julia Evans 用 zine 和漫画讲透 Linux / 网络 / 调试 Hillel Wayne 形式化方法、TLA+、软件正确性 Dave Cheney Go 语言深层机制，必读 Dan Luu 硬核性能剖析 + 工程文化反思 工具与资源 站点 描述 Compiler Explorer 在线编译器，实时看汇编输出 Beej\u0026rsquo;s Guide 经典网络编程与 C 语言指南 The Algorithms 多语言算法实现大全 Quick Reference 各语言/工具 cheat sheet 友情链接 想交换友链？请在评论区留言或发邮件给我，格式：站点名 + URL + 一句话描述。\n","permalink":"https://biribiribird.top/links/","summary":"\u003ch2 id=\"常去的地方\"\u003e常去的地方\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth style=\"text-align: left\"\u003e站点\u003c/th\u003e\n          \u003cth style=\"text-align: left\"\u003e描述\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003ca href=\"http://paulgraham.com/articles.html\"\u003ePaul Graham\u003c/a\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003eEssays — 硅谷最会写文章的程序员\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003ca href=\"https://jvns.ca/\"\u003eJulia Evans\u003c/a\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e用 zine 和漫画讲透 Linux / 网络 / 调试\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003ca href=\"https://www.hillelwayne.com/\"\u003eHillel Wayne\u003c/a\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e形式化方法、TLA+、软件正确性\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003ca href=\"https://dave.cheney.net/\"\u003eDave Cheney\u003c/a\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003eGo 语言深层机制，必读\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003ca href=\"https://danluu.com/\"\u003eDan Luu\u003c/a\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e硬核性能剖析 + 工程文化反思\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"工具与资源\"\u003e工具与资源\u003c/h2\u003e\n\u003ctable\u003e\n  \u003cthead\u003e\n      \u003ctr\u003e\n          \u003cth style=\"text-align: left\"\u003e站点\u003c/th\u003e\n          \u003cth style=\"text-align: left\"\u003e描述\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003ca href=\"https://godbolt.org/\"\u003eCompiler Explorer\u003c/a\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e在线编译器，实时看汇编输出\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003ca href=\"https://beej.us/guide/\"\u003eBeej\u0026rsquo;s Guide\u003c/a\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e经典网络编程与 C 语言指南\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003ca href=\"https://the-algorithms.com/\"\u003eThe Algorithms\u003c/a\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e多语言算法实现大全\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n          \u003ctd style=\"text-align: left\"\u003e\u003ca href=\"https://quickref.me/\"\u003eQuick Reference\u003c/a\u003e\u003c/td\u003e\n          \u003ctd style=\"text-align: left\"\u003e各语言/工具 cheat sheet\u003c/td\u003e\n      \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\u003ch2 id=\"友情链接\"\u003e友情链接\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003e想交换友链？请在评论区留言或发邮件给我，格式：\u003ccode\u003e站点名 + URL + 一句话描述\u003c/code\u003e。\u003c/p\u003e","title":"友链"}]