<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>第 1 章 设计哲学与历史 on Go 语言原本</title><link>http://golang.design/under-the-hood/zh-cn/part1overview/ch01intro/</link><description>Recent content in 第 1 章 设计哲学与历史 on Go 语言原本</description><generator>Hugo</generator><language>zh-cn</language><atom:link href="http://golang.design/under-the-hood/zh-cn/part1overview/ch01intro/index.xml" rel="self" type="application/rss+xml"/><item><title>1.1 编程语言的发展</title><link>http://golang.design/under-the-hood/zh-cn/part1overview/ch01intro/history/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://golang.design/under-the-hood/zh-cn/part1overview/ch01intro/history/</guid><description>&lt;h1 id="11-编程语言的发展"&gt;1.1 编程语言的发展&lt;/h1&gt;
&lt;p&gt;要理解 Go 为何长成今天这样,为何如此克制、如此偏执于编译速度、如此看重并发,得先看它诞生时
面对的是怎样一片语言版图，以及它想替谁解决怎样的痛。Go 不是凭空设计的，它是一群写了一辈子
系统软件的人，对当时主流语言长期不满的一次回应。读懂这段背景，全书后面对调度器、内存模型、
泛型的种种取舍，才有了一个统一的出发点。&lt;/p&gt;
&lt;h2 id="111-语言演化的几条主线"&gt;1.1.1 语言演化的几条主线&lt;/h2&gt;
&lt;p&gt;编程语言半个多世纪的演化，可以粗略看作几股力量的拉锯。沿着几个维度去看，每一门有生命力的
语言，都是在这些维度上做了一组&lt;strong&gt;特定取舍&lt;/strong&gt;的产物，没有哪门语言能在所有维度上同时最优。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;抽象层级&lt;/strong&gt;：从汇编的「直接操纵机器」，到 C 的过程抽象，到 C++/Java 的对象抽象，到函数式
语言的高阶抽象。层级越高，表达越凝练，离机器越远，对性能与可预测性的掌控也越弱。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内存安全&lt;/strong&gt;：从 C 的手工 &lt;code&gt;malloc&lt;/code&gt;/&lt;code&gt;free&lt;/code&gt;（强大但极易出错：悬垂指针、越界、泄漏），到带垃圾
回收的托管语言（消除一大类内存错误，代价是运行时开销与停顿），再到 Rust 的所有权（编译期
保证安全，代价是更陡的学习曲线）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;并发模型&lt;/strong&gt;：从手工线程加锁（危险且难推理），到 CSP / Actor 等更高层的消息传递
（&lt;a href=".././csp"&gt;1.3&lt;/a&gt;），到 &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt; 的无栈协程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类型系统&lt;/strong&gt;：在「静态强类型的安全」与「动态类型的灵活」之间反复摆动；又在「名义类型」与
「结构化类型」（&lt;a href="../../../part2lang/ch04type/interface"&gt;4.2&lt;/a&gt;）之间各有选择。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工程性&lt;/strong&gt;：编译速度、构建模型、工具链、依赖管理。这一维度长期被语言设计者轻视，却恰是
大规模软件协作的命脉,也是 Go 着力最猛的地方。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;把几门有代表性的语言摆在这张坐标上，差异一目了然：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;语言&lt;/th&gt;
 &lt;th&gt;内存管理&lt;/th&gt;
 &lt;th&gt;并发&lt;/th&gt;
 &lt;th&gt;类型&lt;/th&gt;
 &lt;th&gt;编译/执行&lt;/th&gt;
 &lt;th&gt;设计取向&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;C&lt;/td&gt;
 &lt;td&gt;手工&lt;/td&gt;
 &lt;td&gt;线程 + 锁&lt;/td&gt;
 &lt;td&gt;静态、弱&lt;/td&gt;
 &lt;td&gt;编译为本地码&lt;/td&gt;
 &lt;td&gt;贴近机器，零成本抽象&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;C++&lt;/td&gt;
 &lt;td&gt;手工 / RAII&lt;/td&gt;
 &lt;td&gt;线程 + 锁&lt;/td&gt;
 &lt;td&gt;静态、强、复杂&lt;/td&gt;
 &lt;td&gt;编译慢、执行快&lt;/td&gt;
 &lt;td&gt;表达力极大化&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Java&lt;/td&gt;
 &lt;td&gt;GC&lt;/td&gt;
 &lt;td&gt;线程 + 锁 / 虚拟线程&lt;/td&gt;
 &lt;td&gt;静态、名义、反射丰富&lt;/td&gt;
 &lt;td&gt;JIT、运行时重&lt;/td&gt;
 &lt;td&gt;「一次编写，到处运行」&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Python&lt;/td&gt;
 &lt;td&gt;GC（引用计数）&lt;/td&gt;
 &lt;td&gt;GIL + 线程 / async&lt;/td&gt;
 &lt;td&gt;动态&lt;/td&gt;
 &lt;td&gt;解释执行&lt;/td&gt;
 &lt;td&gt;开发效率优先&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Rust&lt;/td&gt;
 &lt;td&gt;所有权&lt;/td&gt;
 &lt;td&gt;线程 + async&lt;/td&gt;
 &lt;td&gt;静态、强、所有权&lt;/td&gt;
 &lt;td&gt;编译慢、执行快&lt;/td&gt;
 &lt;td&gt;安全且零成本&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Go&lt;/td&gt;
 &lt;td&gt;GC&lt;/td&gt;
 &lt;td&gt;goroutine（CSP）&lt;/td&gt;
 &lt;td&gt;静态、结构化接口&lt;/td&gt;
 &lt;td&gt;编译极快、执行快&lt;/td&gt;
 &lt;td&gt;简单、工程友好&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这张表不是为了排座次,没有「最好」的一行，只有「为不同目标做了不同取舍」的若干行。Go 在表里
的位置,带 GC、CSP 并发、结构化接口、编译极快、设计取向是「简单」,正是它要解决的那些痛
逼出来的。&lt;/p&gt;</description></item><item><title>1.2 Go 语言综述</title><link>http://golang.design/under-the-hood/zh-cn/part1overview/ch01intro/go/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://golang.design/under-the-hood/zh-cn/part1overview/ch01intro/go/</guid><description>&lt;h1 id="12-go-语言综述"&gt;1.2 Go 语言综述&lt;/h1&gt;
&lt;p&gt;这一节为全书搭一个骨架。它不是语法手册,Go 的语法在任何入门书里都讲得清楚，重复它没有意义。
我们要做的，是先建立一个&lt;strong&gt;俯瞰全局的视角&lt;/strong&gt;：Go 由哪几层构成、它有哪些&lt;strong&gt;与众不同&lt;/strong&gt;的设计决定、
以及这些决定分别在本书的哪一章展开。读完这一节，再钻进后面任何一章，都不会迷路。&lt;/p&gt;
&lt;h2 id="121-三层视角"&gt;1.2.1 三层视角&lt;/h2&gt;
&lt;p&gt;理解 Go，可以分三层来看，本书也大致按这三层加上历史铺陈来组织。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;语言层&lt;/strong&gt;,你直接书写的东西：语法、类型系统、并发原语、错误处理。它刻意小而正交。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;运行时层&lt;/strong&gt;,与你的程序一起被编译进同一个二进制、在背后默默支撑的「小操作系统」：goroutine
调度器、内存分配器、垃圾回收器、栈管理。这是 Go 最厚重、也最值得剖析的部分。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;工具链层&lt;/strong&gt;,把源码变成可运行、可诊断、可维护程序的机器：编译器、链接器、模块系统、测试与
可观测性工具。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;你的 Go 源码
 │ 编译器 / 链接器（工具链层，第 3、15 章）
 ▼
单个自包含的二进制 ── 内含 runtime（运行时层，第 9–14 章）
 │ 运行时：调度 goroutine、分配内存、回收垃圾、管理栈
 ▼
在操作系统线程上并发执行（语言层语义，第 4–8、10、11 章）
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Go 的一个鲜明特征，是它的&lt;strong&gt;运行时层异常厚重&lt;/strong&gt;。它把调度、垃圾回收、栈管理这些本属操作系统
范畴的复杂度，接管进了语言运行时,以换取上层的简洁：一个 &lt;code&gt;go&lt;/code&gt; 关键字、自动内存管理、可在
任意深度阻塞的 goroutine。本书大半篇幅，正是在剖析这个「藏在二进制里的微型操作系统」。&lt;/p&gt;
&lt;h2 id="122-几个与众不同的设计决定"&gt;1.2.2 几个与众不同的设计决定&lt;/h2&gt;
&lt;p&gt;Go 的气质，集中体现在几个和主流语言不一样的决定上。下面各用一小段代码点出，并指向它在本书
的归属。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;并发是语言的一等公民（CSP）。&lt;/strong&gt; 启动一个并发执行只需 &lt;code&gt;go&lt;/code&gt;，协调用 channel,不必碰线程库与锁。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ch := make(&lt;span style="color:#00f"&gt;chan&lt;/span&gt; &lt;span style="color:#2b91af"&gt;int&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#00f"&gt;go&lt;/span&gt; &lt;span style="color:#00f"&gt;func&lt;/span&gt;() { ch &amp;lt;- compute() }() &lt;span style="color:#008000"&gt;// 启动一个 goroutine，算完把结果送进 channel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;result := &amp;lt;-ch &lt;span style="color:#008000"&gt;// 在此等待并接收，通信即同步&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;这背后是 CSP 思想（&lt;a href=".././csp"&gt;1.3&lt;/a&gt;）、廉价的有栈协程与 M:N 调度器
（&lt;a href="../../part3concurrency/ch09sched"&gt;9&lt;/a&gt;）、以及 channel 的实现（&lt;a href="../../part3concurrency/ch10chan"&gt;10&lt;/a&gt;）。&lt;/p&gt;</description></item><item><title>1.3 顺序进程通讯</title><link>http://golang.design/under-the-hood/zh-cn/part1overview/ch01intro/csp/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>http://golang.design/under-the-hood/zh-cn/part1overview/ch01intro/csp/</guid><description>&lt;h1 id="13-顺序进程通讯"&gt;1.3 顺序进程通讯&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;本节内容提供一个线上演讲：&lt;a href="https://www.youtube.com/watch?v=Z8ZpWVuEx8c"&gt;YouTube 在线&lt;/a&gt;，&lt;a href="https://changkun.de/s/csp/"&gt;Google Slides 讲稿&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Go 并发模型的思想源头，是 Hoare 于 1978 年在 CACM 上提出的&lt;strong&gt;顺序进程通讯&lt;/strong&gt;（Communicating
Sequential Processes, CSP）。这一节从思想史的角度交代这份血脉，它解释了 goroutine 与
channel 为何是今天这个样子。channel 与 select 的实现细节（hchan 的环形缓冲、&lt;code&gt;gopark&lt;/code&gt; 与
&lt;code&gt;goready&lt;/code&gt; 的配对、&lt;code&gt;selectgo&lt;/code&gt; 的两轮加锁），留待 &lt;a href="../../../part3concurrency/ch10chan/readme"&gt;第 10 章&lt;/a&gt;
展开；这里关心的是「为什么是 CSP」，以及这份选择如何塑造了 Go 程序的样貌。&lt;/p&gt;
&lt;h2 id="131-csp-的核心主张"&gt;1.3.1 CSP 的核心主张&lt;/h2&gt;
&lt;p&gt;上个世纪七十年代，多核处理器还是科研主题，尚未进入普通程序员的视野。彼时协调并发实体的手段
已经不少：信号量（Dijkstra, 1965）、监控（Hoare, 1974）、锁与互斥、消息传递。Lauer 与
Needham 1979 年还证明了「消息传递」与「共享内存加锁」在表达力上彼此等价，二者只是同一件事的
两副面孔。Hoare 在这片图景里做出的选择，是把通信（即输入输出）当作编程语言的基本要素，并以
此为唯一的协调手段。&lt;/p&gt;
&lt;p&gt;CSP 的核心是一句反直觉的主张：&lt;strong&gt;进程之间不共享状态，只通过传递消息来协调。&lt;/strong&gt; 在共享内存的
世界里，多个线程读写同一块内存，靠锁来防止彼此踩踏，这既危险（数据竞争、死锁），又难以推理。
CSP 反其道而行：每个顺序进程守着自己的状态，要协作就&lt;strong&gt;发消息&lt;/strong&gt;，通过一次同步的通信动作来交接
数据与控制权。Go 把这条主张凝成那句广为人知的格言：「&lt;strong&gt;不要以共享内存的方式通信，而要以通信的
方式共享内存。&lt;/strong&gt;」&lt;/p&gt;
&lt;p&gt;这里有一处需要澄清的史实，它常被一笔带过，却恰恰是理解 Go 与 CSP 关系的关键。&lt;/p&gt;
&lt;h2 id="132-1978-年的-csp按进程名通信没有-channel"&gt;1.3.2 1978 年的 CSP：按进程名通信，没有 channel&lt;/h2&gt;
&lt;p&gt;读者若翻开 Hoare 1978 年的原始论文，会发现一件出乎意料的事：那门语言里&lt;strong&gt;没有第一类的
channel&lt;/strong&gt;。通信不是把数据投进某条匿名管道，而是&lt;strong&gt;直接指名某个进程&lt;/strong&gt;。两个基本算符是：&lt;/p&gt;</description></item></channel></rss>