<?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; GopherCon</title>
	<atom:link href="http://tonybai.com/tag/gophercon/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>从线下到线上，我的“Go语言进阶课”终于在极客时间与大家见面了！</title>
		<link>https://tonybai.com/2025/05/12/go-advanced-course/</link>
		<comments>https://tonybai.com/2025/05/12/go-advanced-course/#comments</comments>
		<pubDate>Mon, 12 May 2025 00:33:56 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Channel]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[gopherchina]]></category>
		<category><![CDATA[GopherCon]]></category>
		<category><![CDATA[goroutine]]></category>
		<category><![CDATA[Go语言进阶课]]></category>
		<category><![CDATA[Go高级工程师必修课]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[map]]></category>
		<category><![CDATA[MCP]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[pitfall]]></category>
		<category><![CDATA[Pointer]]></category>
		<category><![CDATA[Slice]]></category>
		<category><![CDATA[TIOBE]]></category>
		<category><![CDATA[trap]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[TypeSystem]]></category>
		<category><![CDATA[value]]></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=4687</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2025/05/12/go-advanced-course 大家好，我是Tony Bai。 今天，怀着一丝激动和期待，我想向大家宣布一个酝酿已久的好消息：我的新专栏“TonyBai · Go 语言进阶课” 终于在极客时间正式上架了！ 这门课程的诞生，其实有一段不短的故事。它并非一时兴起，而是源于我对 Go 语言多年实践的沉淀、对 Gopher 们进阶痛点的洞察，以及一份希望能帮助更多开发者突破瓶颈、实现精通的心愿。 缘起：从 GopherChina 的线下训练营开始 故事的起点，要追溯到 GopherChina 2023 大会前夕。当时，我应邀开设了一期名为“Go 高级工程师必修课”的线下训练营。至今还清晰记得，在滴滴的一个会议室里，我与一群对 Go 语言充满热忱的开发者们，共同探讨、深入剖析了 Go 进阶之路上的种种挑战与关键技能。 那次线下课程的反馈非常积极，也让我深刻感受到，许多 Gopher 在掌握了 Go 的基础之后，普遍面临着“如何从熟练到精通”的困惑。他们渴望写出更优雅、更高性能的代码，希望提升复杂项目的设计能力，也期盼着能掌握更硬核的工程实践经验。 同年，我还临危受命，在 GopherChina 2023 上加了一场 “The State Of Go” 的演讲，与大家分享了我对 Go 语言发展趋势的观察与思考。这些经历，都让我更加坚信，系统性地梳理和分享 Go 语言的进阶知识，是非常有价值且必要的。 打磨：从线下到线上，不变的是匠心 将线下课程的精华沉淀下来，打磨成一门更普惠、更系统的线上专栏，这个想法在 2024 年就已萌生。但由于种种原因，特别是档期的冲突，这个计划暂时搁置了。 直到 2025 年，我与极客时间的老师们再次携手，投入了大量心血，对课程内容进行了反复打磨和精心编排。我们不仅希望传递知识，更希望启发思考，帮助大家建立起真正的“Go 语言设计思维和工程思维”。 正如我在专栏开篇词中提到的，如果你也正面临这些困惑： 感觉到了瓶颈？ [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2025/go-advanced-course-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2025/05/12/go-advanced-course">本文永久链接</a> &#8211; https://tonybai.com/2025/05/12/go-advanced-course</p>
<p>大家好，我是Tony Bai。</p>
<p>今天，怀着一丝激动和期待，我想向大家宣布一个酝酿已久的好消息：我的新专栏<strong>“<a href="http://gk.link/a/12yGY">TonyBai · Go 语言进阶课</a>”</strong> 终于在极客时间正式上架了！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/go-advanced-course-1.jpg" alt="" /></p>
<p>这门课程的诞生，其实有一段不短的故事。它并非一时兴起，而是源于我对 Go 语言多年实践的沉淀、对 Gopher 们进阶痛点的洞察，以及一份希望能帮助更多开发者突破瓶颈、实现精通的心愿。</p>
<h2>缘起：从 GopherChina 的线下训练营开始</h2>
<p>故事的起点，要追溯到 GopherChina 2023 大会前夕。当时，我应邀开设了一期名为“Go 高级工程师必修课”的线下训练营。至今还清晰记得，在滴滴的一个会议室里，我与一群对 Go 语言充满热忱的开发者们，共同探讨、深入剖析了 Go 进阶之路上的种种挑战与关键技能。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-advanced-training-2023-2.png" alt="GopherChina 2023 “Go高级工程师必修课”线下训练营图片" /></p>
<p>那次线下课程的反馈非常积极，也让我深刻感受到，许多 Gopher 在掌握了 Go 的基础之后，普遍面临着“如何从熟练到精通”的困惑。他们渴望写出更优雅、更高性能的代码，希望提升复杂项目的设计能力，也期盼着能掌握更硬核的工程实践经验。</p>
<p>同年，我还临危受命，在 GopherChina 2023 上加了一场 “The State Of Go” 的演讲，与大家分享了我对 Go 语言发展趋势的观察与思考。这些经历，都让我更加坚信，系统性地梳理和分享 Go 语言的进阶知识，是非常有价值且必要的。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/go-advanced-course-2.png" alt="" /></p>
<h2>打磨：从线下到线上，不变的是匠心</h2>
<p>将线下课程的精华沉淀下来，打磨成一门更普惠、更系统的线上专栏，这个想法在 2024 年就已萌生。但由于种种原因，特别是档期的冲突，这个计划暂时搁置了。</p>
<p>直到 2025 年，我与极客时间的老师们再次携手，投入了大量心血，对课程内容进行了反复打磨和精心编排。我们不仅希望传递知识，更希望启发思考，帮助大家建立起真正的“Go 语言设计思维和工程思维”。</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/go-advanced-course-3.jpg" alt="" /></p>
<p>正如我在专栏开篇词中提到的，如果你也正面临这些困惑：</p>
<ul>
<li><strong>感觉到了瓶颈？</strong> 写了不少 Go 代码，但总觉得离“精通”还差一口气？</li>
<li><strong>设计能力跟不上？</strong> 面对复杂的业务需求，如何进行合理的项目布局、包设计、接口设计？</li>
<li><strong>工程实践经验不足？</strong> 知道要测试、要监控、要优化，但具体到 Go 项目，如何落地？</li>
</ul>
<p>那么，这门“Go 语言进阶课”正是为你量身打造的。</p>
<h2>蜕变：从“熟练工”到“专家”，三大模块助你突破</h2>
<p>课程摒弃了简单罗列知识点的方式，聚焦于 Go 工程师能力提升的三个核心维度，精心设计了三大模块：</p>
<ul>
<li><strong>模块一：夯实基础，突破语法认知瓶颈</strong><br />
这里我们不满足于“知道”，而是追求“理解”。深入类型系统、值与指针、切片与 map 陷阱、接口与组合、泛型等核心概念的底层逻辑与设计哲学，让你写出更地道、更健壮的 Go 代码。</li>
<li><strong>模块二：设计先行，奠定高质量代码基础</strong><br />
从宏观的项目布局、包设计，到具体的并发模型选择、接口设计原则，再到实用的错误处理策略和 API 设计规范。提升你的软件设计能力，让你能驾驭更复杂的项目。</li>
<li><strong>模块三：工程实践，锻造生产级 Go 服务</strong><br />
聚焦于将 Go 代码变成可靠线上服务的关键环节。从应用骨架、核心组件、可观测性，到故障排查、性能调优、云原生部署以及与 AI 大模型集成，全是硬核干货。</li>
</ul>
<p>此外，课程还安排了<strong>实战串讲项目</strong>，带你将学到的知识融会贯通，亲手构建并完善一个真实的 Go 服务。</p>
<p>我深知，从“熟练”到“精通”，不是一蹴而就的。但这门课程，希望能成为你进阶路上的助推器和导航仪。它凝聚了我 20 多年的行业经验，特别是我在电信领域高并发网关和智能网联汽车车云平台使用 Go 语言构建大规模生产系统的实践与思考。</p>
<p>在课程中，你不仅能学到 Go 的高级特性和用法，更能体会到 Go 语言“组合优于继承”、“显式错误处理”等设计哲学的精髓，以及在大模型时代如何让 AI 赋能你的 Go 应用。</p>
<h2>现在，是时候了！</h2>
<p>正如我在开篇词中强调的，Go 语言正迎来它的黄金十年。从 TIOBE 榜单的稳步攀升（2025 年 4 月份额已突破 3%），到全球 GopherCon 的回归，再到各大主流厂商对 Go 的拥抱（比如 TypeScript 编译器向 Go 移植、Grafana 和 GitHub 用 Go 重写 MCP Server），都预示着 Go 在云原生、微服务、AI 后端等领域的强劲势头。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/go-advanced-course-3.png" alt="" /><br />
<img src="https://tonybai.com/wp-content/uploads/2025/go-advanced-course-4.png" alt="" /></p>
<p>现在，正是学习和进阶 Go 的最佳时机！</p>
<p>如果你渴望突破瓶颈，实现从“Go 熟练工”到“Go 专家”的蜕变，那么，我在极客时间的《TonyBai · Go 语言进阶课》等你！</p>
<p><strong>扫描下方二维码或点击[阅读原文]，立即加入，开启你的 Go 语言精进之旅！</strong></p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/go-advanced-course-4.png" alt="" /></p>
<p>期待与你在课程中相遇，共同探索 Go 语言的精妙与强大！</p>
<p>最后，一个小小的请求：</p>
<p>如果你身边有正在 Go 语言进阶道路上摸索，或者渴望提升 Go 工程实践与设计能力的 Gopher 朋友、同事，<strong>请将这篇文章或课程信息分享给他们</strong>。 每一份善意的传递，都可能为他人的技术成长点亮一盏灯。</p>
<p>也欢迎大家在评论区踊跃交流，分享你对 Go 进阶的困惑、经验或对课程的期待。让我们一起，在 Go 的世界里，持续学习，共同进步！</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; 2025, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2025/05/12/go-advanced-course/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>2024年Go语言盘点：排名历史新高，团队新老传承</title>
		<link>https://tonybai.com/2025/01/06/the-2024-review-of-go-programming-language/</link>
		<comments>https://tonybai.com/2025/01/06/the-2024-review-of-go-programming-language/#comments</comments>
		<pubDate>Sun, 05 Jan 2025 21:48:41 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[AustinClements]]></category>
		<category><![CDATA[Cgo]]></category>
		<category><![CDATA[Changelog]]></category>
		<category><![CDATA[CherryMui]]></category>
		<category><![CDATA[Claude]]></category>
		<category><![CDATA[devirtualize]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[for-range]]></category>
		<category><![CDATA[Gartner]]></category>
		<category><![CDATA[GC]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[go.mod]]></category>
		<category><![CDATA[go.work]]></category>
		<category><![CDATA[go1.23]]></category>
		<category><![CDATA[go1.24]]></category>
		<category><![CDATA[gobuild]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[gomodule]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[gopherchina]]></category>
		<category><![CDATA[GopherCon]]></category>
		<category><![CDATA[GopherConAfrica]]></category>
		<category><![CDATA[gotest]]></category>
		<category><![CDATA[GoTime]]></category>
		<category><![CDATA[hype-cycle]]></category>
		<category><![CDATA[IEEE]]></category>
		<category><![CDATA[Inline]]></category>
		<category><![CDATA[loopvar]]></category>
		<category><![CDATA[octoverse]]></category>
		<category><![CDATA[ollama]]></category>
		<category><![CDATA[openai]]></category>
		<category><![CDATA[oscar]]></category>
		<category><![CDATA[PGO]]></category>
		<category><![CDATA[reddit]]></category>
		<category><![CDATA[RussCox]]></category>
		<category><![CDATA[SDK]]></category>
		<category><![CDATA[structs]]></category>
		<category><![CDATA[Telemetry]]></category>
		<category><![CDATA[ticker]]></category>
		<category><![CDATA[Timer]]></category>
		<category><![CDATA[TIOBE]]></category>
		<category><![CDATA[typealias]]></category>
		<category><![CDATA[typeparameter]]></category>
		<category><![CDATA[unique]]></category>
		<category><![CDATA[vendor]]></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=4456</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2024/01/06/the-2024-review-of-go-programming-language 2024年底，由于感染了甲流，我在家卧床休息了两天，原定于2024年进行的Go语言盘点写作因此被迫推迟。不过，我始终相信：迟到但不会缺席。在2025年元旦的第一天，我终于开始了这篇博客的撰写。 时间过得真快，《2023年Go语言盘点：稳中求新，稳中求变》依然历历在目。转眼之间，一年365天过去了，发生了许多事情，甚至有些记忆已在脑海中模糊或消逝。在这里，我将带你盘点那些关于Go的重要时刻，唤起你对Go的美好回忆。 回顾整个2024年，如果非要用一句话来形容Go语言的状态，我会选择：Go完成了技术成熟度曲线中的“稳步爬升复苏期”，开始进入“生产成熟期”。这一点在Go的排名中得到了直接体现，并在Go社区的活跃度方面得到了间接的印证。而Go的年中换帅似乎也预示着这是一个新的起点！在过去一年中，得益于Go团队和社区的共同努力，Go发布了许多值得关注的新特性。 接下来，我将为大家逐一详细介绍！ 1. Go排名创历史新高 说到编程语言排名，程序员们首先想到的就是TIOBE！在2024年的TIOBE排行榜上，尽管Go语言没有像AI时代的霸主语言Python那样耀眼，但跻身前十并站稳第七名这一成绩也足以让其他语言羡慕不已！ 图：2024年12月TIOBE排名TOP 10 而从2009年开源至今，Go在TIOBE排名走势如下： 图：2010年-2024年TIOBE排行榜Go语言走势 了解Go历史的朋友都知道，Go语言真正具备生产级成熟度是从2015年的Go 1.5版本开始的。按照技术成熟度曲线的划分，2015年之前及其后的一段时间可以视为技术萌芽期。从曲线中可以看出，2017年时达到了期望膨胀期的峰值。此后，Go经历了一段“漫长”的泡沫破裂低谷期以及稳步爬升的复苏期。从2023年开始，到2024年末，Go语言复苏的速度日益加快！目前来看，如无意外，Go将进入技术成熟度曲线的下一阶段：生产成熟期！我曾提到过：绝大多数主流编程语言将在其诞生后的第15至第20年间大步前进。按照这个编程语言的一般规律，刚刚迈过开源第15个年头的Go刚刚迈进自己的黄金5-10年。 当然，单看TIOBE单一榜单似乎说服力不足，我们再来看看今年的Github octoverse报告。在这份报告中，Go依旧稳居github热门编程语言前10(如下图)，这一位置已经保持了三年多了！ 图：2024年Github最热门编程语言排行榜 此外，在2024年年中发布的“IEEE Spectrum 2024编程语言排行榜”中，Go在Spectrum排名和Trending排名中分列第8位和第7位。 除了排行榜之外，通过Reddit中编程语言论坛的活跃度也可以看出Go语言在全球的受欢迎程度和用户广度。以下是2025年1月1日Reddit上最活跃的9门编程语言子论坛的实时状态截图： 图：2025.1.1 Reddit编程语言子论坛状态对比 我们看到Go子论坛在成员数量和某一时刻的在线人数上都表现良好。此外，如果你是长期关注Reddit Go论坛的Gopher，一定注意到自2024年初以来，Go论坛的人气迅速增长，日均帖子数相比前两年显著增加，其中很多都是新加入Go阵营的初学者！ 注：Rust的人气是真高啊，online人数断崖领先！ 编程语言技术大会是衡量语言流行度和受欢迎程度的另一重要风向标。自从全球从新冠疫情中恢复后，GopherCon逐渐在各地线下恢复，到了2024年基本回到了疫情前的状态，甚至在一些地方的GopherCon还超越了以往的受欢迎程度。例如，2024年GopherCon欧洲大会破例举办了两次。此外，首届在非洲举行的GopherCon Africa也于2024年10月份在肯尼亚首都内罗毕成功举行！唯一的遗憾是GopherChina在2024年缺席，这或许与国内的经济形势有关。 Go的增长趋势来的有些快，不知道是否是得益于AI应用的快速发展！但就像Go团队前成员Jaana Dogan(Rakyll)所说的那样： Go将成为AI时代重要的AI应用开发语言！AI大模型三强：OpenAI、Claude和Google都提供了对Go SDK的官方支持： OpenAI Go SDK &#8211; https://github.com/openai/openai-go Claude GO SDK &#8211; https://github.com/anthropics/anthropic-sdk-go Google AI Go SDK &#8211; https://github.com/google/generative-ai-go 此外，提到Go和AI大模型，我们不得不提及一个重量级的开源项目——Ollama，它可以说是当前私有部署和使用开源大模型的事实标准！在2024年的用户调查报告中，Go团队还特别关注了用户对使用Go开发AI应用的需求，并将AI应用开发视为Go应用的下一个重要赛道。此外，Russ Cox也积极参与这一领域，开源了专用于开源项目运营维护的AI机器人：Oscar，同时探索Go在AI领域的应用。 如果说Go的排名再创新高让Gopher和Go社区对Go充满了更多自信，那么Go团队的换帅则向整个编程语言界展示了团队的传承与发展！ 2. Go团队换帅展示团队传承 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/the-2024-review-of-go-programming-language-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2024/01/06/the-2024-review-of-go-programming-language">本文永久链接</a> &#8211; https://tonybai.com/2024/01/06/the-2024-review-of-go-programming-language</p>
<p>2024年底，由于感染了甲流，我在家卧床休息了两天，原定于2024年进行的Go语言盘点写作因此被迫推迟。不过，我始终相信：迟到但不会缺席。在2025年元旦的第一天，我终于开始了这篇博客的撰写。</p>
<p>时间过得真快，《<a href="https://tonybai.com/2023/12/31/the-2023-review-of-go-progrmming-language/">2023年Go语言盘点：稳中求新，稳中求变</a>》依然历历在目。转眼之间，一年365天过去了，发生了许多事情，甚至有些记忆已在脑海中模糊或消逝。在这里，我将带你盘点那些关于Go的重要时刻，唤起你对Go的美好回忆。</p>
<p>回顾整个2024年，如果非要用一句话来形容Go语言的状态，我会选择：<strong>Go完成了<a href="https://www.gartner.com/cn/research/methodologies/gartner-hype-cycle">技术成熟度曲线</a>中的“稳步爬升复苏期”，开始进入“生产成熟期”</strong>。这一点在Go的排名中得到了直接体现，并在Go社区的活跃度方面得到了间接的印证。而<a href="https://tonybai.com/2024/10/10/pass-torch-to-go-new-leadership-team">Go的年中换帅</a>似乎也<strong>预示着这是一个新的起点</strong>！在过去一年中，得益于Go团队和社区的共同努力，Go发布了许多值得关注的新特性。</p>
<p>接下来，我将为大家逐一详细介绍！</p>
<h2>1. Go排名创历史新高</h2>
<p>说到编程语言排名，程序员们首先想到的就是TIOBE！在2024年的<a href="https://www.tiobe.com/tiobe-index/">TIOBE排行榜</a>上，尽管Go语言没有像<a href="https://tonybai.com/2024/10/14/programming-in-ai-era">AI时代</a>的霸主语言Python那样耀眼，但跻身前十并站稳第七名这一成绩也足以让其他语言羡慕不已！</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2024-review-of-go-programming-language-4.png" alt="" /><br />
<center>图：2024年12月TIOBE排名TOP 10</center></p>
<p>而从2009年开源至今，Go在TIOBE排名走势如下：</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2024-review-of-go-programming-language-2.png" alt="" /><br />
<center>图：2010年-2024年TIOBE排行榜Go语言走势</center></p>
<p>了解Go历史的朋友都知道，Go语言真正具备生产级成熟度是从2015年的Go 1.5版本开始的。按照技术成熟度曲线的划分，2015年之前及其后的一段时间可以视为技术萌芽期。从曲线中可以看出，2017年时达到了期望膨胀期的峰值。此后，Go经历了一段“漫长”的泡沫破裂低谷期以及稳步爬升的复苏期。从2023年开始，到2024年末，Go语言复苏的速度日益加快！目前来看，如无意外，Go将进入技术成熟度曲线的下一阶段：生产成熟期！我曾提到过：<strong>绝大多数主流编程语言将在其诞生后的第15至第20年间大步前进</strong>。按照这个编程语言的一般规律，刚刚<a href="https://tonybai.com/2024/11/12/go-turns-15">迈过开源第15个年头的Go</a>刚刚迈进自己的黄金5-10年。</p>
<p>当然，单看TIOBE单一榜单似乎说服力不足，我们再来看看<a href="https://github.blog/news-insights/octoverse/octoverse-2024/#the-most-popular-programming-languages">今年的Github octoverse报告</a>。在这份报告中，Go依旧稳居github热门编程语言前10(如下图)，这一位置已经保持了三年多了！</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2024-review-of-go-programming-language-3.png" alt="" /><br />
<center>图：2024年Github最热门编程语言排行榜</center></p>
<p>此外，在2024年年中发布的“<a href="https://mp.weixin.qq.com/s/nLgg18iG3ZIt-ojHqPuqRA">IEEE Spectrum 2024编程语言排行榜</a>”中，Go在Spectrum排名和Trending排名中分列第8位和第7位。</p>
<p>除了排行榜之外，通过Reddit中编程语言论坛的活跃度也可以看出Go语言在全球的受欢迎程度和用户广度。以下是2025年1月1日Reddit上最活跃的9门编程语言子论坛的实时状态截图：</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2024-review-of-go-programming-language-5.png" alt="" /><br />
<center>图：2025.1.1 Reddit编程语言子论坛状态对比</center></p>
<p>我们看到Go子论坛在成员数量和某一时刻的在线人数上都表现良好。此外，如果你是长期关注Reddit Go论坛的Gopher，一定注意到自2024年初以来，Go论坛的人气迅速增长，日均帖子数相比前两年显著增加，其中很多都是新加入Go阵营的初学者！</p>
<blockquote>
<p>注：<a href="https://tonybai.com/tag/rust">Rust</a>的人气是真高啊，online人数断崖领先！</p>
</blockquote>
<p>编程语言技术大会是衡量语言流行度和受欢迎程度的另一重要风向标。自从全球从新冠疫情中恢复后，GopherCon逐渐在各地线下恢复，到了2024年基本回到了疫情前的状态，甚至在一些地方的GopherCon还超越了以往的受欢迎程度。例如，2024年GopherCon欧洲大会破例举办了两次。此外，<a href="https://dev.to/johneliud/my-experience-attending-gophercon-africa-2024-171e">首届在非洲举行的GopherCon Africa</a>也于2024年10月份在肯尼亚首都内罗毕成功举行！唯一的遗憾是<strong>GopherChina在2024年缺席</strong>，这或许与国内的经济形势有关。</p>
<p>Go的增长趋势来的有些快，不知道是否是得益于AI应用的快速发展！但就像Go团队前成员<a href="https://github.com/rakyll">Jaana Dogan(Rakyll)</a>所说的那样：</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2024-review-of-go-programming-language-6.png" alt="" /></p>
<p>Go将成为AI时代重要的AI应用开发语言！AI大模型三强：OpenAI、Claude和Google都提供了对Go SDK的官方支持：</p>
<ul>
<li>OpenAI Go SDK &#8211; https://github.com/openai/openai-go</li>
<li>Claude GO SDK &#8211; https://github.com/anthropics/anthropic-sdk-go</li>
<li>Google AI Go SDK &#8211; https://github.com/google/generative-ai-go</li>
</ul>
<p>此外，提到Go和AI大模型，我们不得不提及一个重量级的开源项目——<a href="https://ollama.com/">Ollama</a>，它可以说是当前私有部署和使用开源大模型的事实标准！在<a href="https://go.dev/blog/survey2024-h1-results">2024年的用户调查报告</a>中，Go团队还特别关注了用户对使用Go开发AI应用的需求，并将AI应用开发视为Go应用的下一个重要赛道。此外，Russ Cox也积极参与这一领域，开源了专<a href="https://mp.weixin.qq.com/s/dbuR1oRavvaemUPA7uhyag">用于开源项目运营维护的AI机器人：Oscar</a>，同时探索Go在AI领域的应用。</p>
<p>如果说Go的排名再创新高让Gopher和Go社区对Go充满了更多自信，那么Go团队的换帅则向整个编程语言界展示了团队的传承与发展！</p>
<h2>2. <a href="https://mp.weixin.qq.com/s/2Sy6K_dU1j3tZZiyyfCTDQ">Go团队换帅展示团队传承</a></h2>
<p>对于Go团队来说，2024年的最大的事件不是<a href="https://tonybai.com/2024/02/18/some-changes-in-go-1-22">Go 1.22</a>或<a href="https://tonybai.com/2024/08/19/some-changes-in-go-1-23/">Go 1.23</a>的发布，而是<strong>团队换帅</strong>。</p>
<p>2024年中旬，Go团队的技术负责人Russ Cox宣布，他将于2024年9月1日起卸任Go项目的技术领导职务。自2008年参与Go项目以来，Russ于2012年成为其技术负责人。在过去的12年里，他引领Go语言从一个实验性项目成长为当今最受欢迎的编程语言之一。在他的带领下，Go凭借简洁的语法、高效的并发模型和强大的标准库赢得了众多开发者的青睐，并在云计算、微服务和DevOps等领域得到了广泛应用。</p>
<p>Russ分享了他卸任的想法，表示这一决定是经过深思熟虑的，是自然发展的结果。他认为，尽管长期稳定的领导对大型项目至关重要，但领导层的变动也能为项目注入新的活力和视角。他强调，定期更换领导者是非常重要的，这有助于引入新思想并防止项目陷入停滞。</p>
<p>接替Russ Cox的是Austin Clements，他将成为新的Go技术负责人，同时领导Google的Go团队和整个Go项目。Austin自2014年起就在Google从事与Go相关的工作，拥有丰富的经验和深厚的技术背景。同时，Cherry Mui将接手负责编译器和运行时等“Go核心”领域的工作。Cherry自2016年加入Google，在Go的核心开发领域表现出色。Russ Cox对这两位新领导给予了高度评价，称赞他们具备卓越的判断力以及对Go语言和其运行系统的广泛而深入的理解。</p>
<p>通过9月份到12月份的角色过期期的观察来看，两位“新负责人”的表现是中规中矩，沿袭了Russ Cox之前确定的Go项目管理框架，Cherry Mui在Go core领域表现的十分积极，这从”<a href="https://github.com/golang/go/issues/43930">Go compiler and runtime meeting notes</a>“的记录中可见一斑！</p>
<p>在<a href="https://changelog.com/gotime/333">第333期GoTime播客</a>中，两位新leader也初步分享了他们对后续Go演进的一些想法。</p>
<p>Austin强调，虽然Go保持着稳定和简洁，但它必须继续演进。他的首要目标之一是改善Go的可扩展性，无论是在开发过程中还是在背后的工程流程中。他希望通过提高透明度和扩大社区参与度，赋能社区，创建一个能够更好整合用户反馈的平台（可能是一个论坛），使贡献者能够开发与核心团队目标一致的工具和解决方案。在性能改进方面，Austin长期致力于优化Go的垃圾回收系统，目前正在试验一种新算法，幽默地称其为“绿茶”，旨在优化资源使用，进一步提升Go在越来越大系统上的扩展能力。</p>
<p>Cherry则指出，Go的用户基础正在快速增长，而核心团队的资源却有限。她的任务是确保Go平台能够支持这一日益增长的社区，无论是通过构建更好的API还是平台，帮助用户在Go的基础上开发更强大的工具和解决方案。在技术扩展性方面，Cherry也表达了自己的关注。随着计算能力的提升，核心数量和内存容量不断增加，Go需要适应，以高效处理更大的工作负载。Cherry表示，她非常期待与社区中的工程师合作，解决这些挑战，保持Go简单且可扩展的声誉。</p>
<p>从两位领导的想法与目标中，我们可以看到Go团队传承的文化。对于这样的“换帅”，Go社区应充满信心。</p>
<blockquote>
<p>注：<a href="https://changelog.com/gotime">GoTime博客</a>在完成其<a href="https://changelog.com/gotime">第340期内容</a>后，因平台方Changelog的变动宣布停播了！</p>
</blockquote>
<h2>3. Go Release新特性一览</h2>
<p>对于已经过了15个生日的Go来说，其演进的节奏已经非常稳定和成熟了。2024年，Go平稳地发布了两个重要版本：Go 1.22和Go 1.23。下面我们就来简单浏览一下这两个版本的主要新特性。</p>
<h3>3.1 Go 1.22主要新特性</h3>
<h4>语言特性</h4>
<ul>
<li>loopvar语义修正：for循环中通过短声明定义的循环变量，由整个循环共享一个实例变为每次迭代定义一个实例。这是 Go 语言发展历史上第一次真正的填语义层面的“坑”。</li>
<li>for range支持整型表达式：for range循环可以遍历整型范围，如for i := range 10。</li>
</ul>
<h4>编译器和运行时</h4>
<ul>
<li>PGO优化增强：基于PGO的构建可以实现更高比例的调用去虚拟化(devirtualize)，带来性能提升。</li>
<li>编译器优化：编译器可以更多地运用devirtualize和inline技术进行优化。</li>
<li>运行时优化：运行时可以使基于类型的垃圾收集的元数据更接近每个堆对象，从而降低CPU和内存开销。</li>
</ul>
<h4>工具链</h4>
<ul>
<li>go work支持vendor：go work命令可以管理vendor目录，并且支持使用go build -mod=vendor构建。</li>
<li>go mod init改进：不再尝试导入其他vendor工具(比如Gopkg)的配置文件。</li>
<li>go test -cover改进： 对于没有测试文件的包，会报告覆盖率为0.0%。</li>
</ul>
<h4>标准库</h4>
<ul>
<li>math/rand/v2: 标准库第一个V2版本包。</li>
<li>增强http.ServeMux的表达能力: 新版ServeMux支持静态路由、通配符、主机匹配和变量捕获。</li>
</ul>
<h3>3.2 Go 1.23 主要新特性</h3>
<h4>语言特性</h4>
<ul>
<li>自定义函数迭代器：for range语句支持遍历用户自定义的集合类型，需要定义满足特定签名的迭代器函数。</li>
<li>别名中增加泛型参数：支持在类型别名定义中使用类型参数，如：</li>
</ul>
<pre><code>type MySlice[T any] = []T
</code></pre>
<h4>编译器与运行时</h4>
<ul>
<li>PGO构建速度提升: 该版本优化后，PGO带来的编译开销显著降低。</li>
<li>限制对linkname的使用: Go 1.23禁止使用linkname指令引用标准库中未标记的内部符号。</li>
</ul>
<h4>工具链</h4>
<ul>
<li>Telemetry (遥测): go工具链程序收集性能和使用数据的系统，且支持go telemetry on|off|local命令。</li>
<li>go env -changed: go env子命令增加-changed选项，可以查看当前Go环境中设置的Go环境变量值与默认值有差异的项的值。</li>
<li>go mod tidy -diff: go mod tidy增加-diff选项，只打印更新信息但不做实际更新。</li>
<li>go.mod中增加godebug指示符: 可以通过该指示符设置特定的GODEBUG选项。</li>
</ul>
<h4>标准库</h4>
<ul>
<li>Timer/Ticker变化: Timer和Ticker的GC不再需要Stop方法，Stop/Reset后不再接收旧值。</li>
<li>structs包: 添加一个零size的类型HostLayout，用于控制编译器对结构体类型的布局方式。</li>
<li>unique包: 新增了unique包，用于处理唯一值的集合。</li>
<li>iter包:  新增了iter包，并增加了函数迭代器相关的实用函数到maps、slices等包中。</li>
</ul>
<p>更多更详细关于Go新特性的内容，请阅读《<a href="https://tonybai.com/2024/02/18/some-changes-in-go-1-22/">Go 1.22中值得关注的几个变化</a>》和《<a href="https://tonybai.com/2024/08/19/some-changes-in-go-1-23/">Go 1.23中值得关注的几个变化</a>》。</p>
<h2>4. 2025展望</h2>
<p>按照Go演进的一贯风格，我本不该对Go抱有过多期待^_^，但还是忍不住想说几句。</p>
<p><a href="https://tonybai.com/2024/08/17/go-the-c-language-of-the-internet-era-come-true/">Go已经稳稳地占据了云计算领域的头部后端编程语言地位</a>，在多个编程语言排行榜上名列前茅，Go社区也在健康快速地发展。然而，机遇与风险总是并存。</p>
<p>虽然Go在云原生、Web服务、微服务、API和CLI开发方面拥有明显优势，但也面临着来自Rust等语言的挑战。Go需要进一步巩固其在这些优势领域的地位，同时探索一些能够发挥自身优势的新方向，例如AI应用开发等。</p>
<p>同时，我们期待新一代Go团队领导者，尤其是来自Go编译器和运行时组的领导者们，能够<strong>深入打磨和优化Go语言的编译器、运行时性能以及语言互操作性</strong>。毕竟，谁不喜欢那种因性能自然增长而带来的愉悦感，以及借助其他语言优势生态快速完成功能的灵活性呢!</p>
<p>最后，感谢Go团队和Go社区在Go语言演进发展上做出的贡献，希望Go越走越好！</p>
<hr />
<p><a href="https://public.zsxq.com/groups/51284458844544">Gopher部落知识星球</a>在2024年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。同时，我们也会加强代码质量和最佳实践的分享，包括如何编写简洁、可读、可测试的Go代码。此外，我们还会加强星友之间的交流和互动。欢迎大家踊跃提问，分享心得，讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落，享受coding的快乐! 欢迎大家踊跃加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-tribe-zsxq-small-card.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/go-programming-from-beginner-to-master-qr.png" alt="img{512x368}" /></p>
<p><img src="http://image.tonybai.com/img/tonybai/go-first-course-banner.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/imooc-go-column-pgo-with-qr.jpg" alt="img{512x368}" /></p>
<p>著名云主机服务厂商DigitalOcean发布最新的主机计划，入门级Droplet配置升级为：1 core CPU、1G内存、25G高速SSD，价格5$/月。有使用DigitalOcean需求的朋友，可以打开这个<a href="https://m.do.co/c/bff6eed92687">链接地址</a>：https://m.do.co/c/bff6eed92687 开启你的DO主机之路。</p>
<p>Gopher Daily(Gopher每日新闻) &#8211; https://gopherdaily.tonybai.com</p>
<p>我的联系方式：</p>
<ul>
<li>微博(暂不可用)：https://weibo.com/bigwhite20xx</li>
<li>微博2：https://weibo.com/u/6484441286</li>
<li>博客：tonybai.com</li>
<li>github: https://github.com/bigwhite</li>
<li>Gopher Daily归档 &#8211; https://github.com/bigwhite/gopherdaily</li>
<li>Gopher Daily Feed订阅 &#8211; https://gopherdaily.tonybai.com/feed</li>
</ul>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。</p>
<p style='text-align:left'>&copy; 2025, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2025/01/06/the-2024-review-of-go-programming-language/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Go map使用Swiss Table重新实现，性能最高提升近50%</title>
		<link>https://tonybai.com/2024/11/14/go-map-use-swiss-table/</link>
		<comments>https://tonybai.com/2024/11/14/go-map-use-swiss-table/#comments</comments>
		<pubDate>Wed, 13 Nov 2024 22:53:32 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[abseil]]></category>
		<category><![CDATA[AustinClements]]></category>
		<category><![CDATA[bucket]]></category>
		<category><![CDATA[bytedance]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[chaining]]></category>
		<category><![CDATA[collision]]></category>
		<category><![CDATA[control-bit]]></category>
		<category><![CDATA[Cpp]]></category>
		<category><![CDATA[flat_hash_map]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[go1.24]]></category>
		<category><![CDATA[GOEXPERIMENT]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[GopherCon]]></category>
		<category><![CDATA[gotip]]></category>
		<category><![CDATA[group]]></category>
		<category><![CDATA[group-probing]]></category>
		<category><![CDATA[grow]]></category>
		<category><![CDATA[H1]]></category>
		<category><![CDATA[H2]]></category>
		<category><![CDATA[hash]]></category>
		<category><![CDATA[hashfunction]]></category>
		<category><![CDATA[hashmap]]></category>
		<category><![CDATA[Iterator]]></category>
		<category><![CDATA[KeithRandall]]></category>
		<category><![CDATA[key]]></category>
		<category><![CDATA[map]]></category>
		<category><![CDATA[mapaccess]]></category>
		<category><![CDATA[mapassign]]></category>
		<category><![CDATA[metadata]]></category>
		<category><![CDATA[open-addressing]]></category>
		<category><![CDATA[rehash]]></category>
		<category><![CDATA[Rust]]></category>
		<category><![CDATA[seed]]></category>
		<category><![CDATA[shrink]]></category>
		<category><![CDATA[SIMD]]></category>
		<category><![CDATA[slot]]></category>
		<category><![CDATA[SSE2]]></category>
		<category><![CDATA[std]]></category>
		<category><![CDATA[swissmap]]></category>
		<category><![CDATA[swisstable]]></category>
		<category><![CDATA[unordered_map]]></category>
		<category><![CDATA[value]]></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=4391</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2024/11/14/go-map-use-swiss-table 在2024月11月5日的Go compiler and runtime meeting notes中，我们注意到了一段重要内容，如下图红框所示： 这表明，来自字节的一位工程师在两年多前提出的“使用Swiss table重新实现Go map”的建议即将落地，目前该issue已经被纳入Go 1.24里程碑。 Swiss Table是由Google工程师于2017年开发的一种高效哈希表实现，旨在优化内存使用和提升性能，解决Google内部代码库中广泛使用的std::unordered_map所面临的性能问题。Google工程师Matt Kulukundis在2017年CppCon大会上详细介绍了他们在Swiss Table上的工作： 目前，Swiss Table已被应用于多种编程语言，包括C++ Abseil库的flat_hash_map(可替换std::unordered_map)、Rust标准库Hashmap的默认实现等。 Swiss Table的出色表现是字节工程师提出这一问题的直接原因。字节跳动作为国内使用Go语言较为广泛的大厂。据issue描述，Go map的CPU消耗约占服务总体开销的4%。其中，map的插入（mapassign）和访问（mapaccess）操作的CPU消耗几乎是1:1。大家可千万不能小看4%这个数字，以字节、Google这样大厂的体量，减少1%也意味着真金白银的大幅节省。 Swiss Table被视为解决这一问题的潜在方案。字节工程师初版实现的基准测试结果显示，与原实现相比，Swiss Table在查询、插入和删除操作上均提升了20%至50%的性能，尤其是在处理大hashmap时表现尤为突出；迭代性能提升了10%；内存使用减少了0%至25%，并且不再消耗额外内存。 这些显著的性能提升引起了Go编译器和运行时团队的关注，特别是当时负责该子团队的Austin Clements。在经过两年多的实验和评估后，Go团队成员Michael Pratt基于Swiss Table实现的internal/runtime/maps最终成为Go map的底层默认实现。 在本文中，我们将简单介绍Swiss Table这一高效的哈希表实现算法，并提前看一下Go map的Swiss Table实现。 在进入swiss table工作原理介绍之前，我们先来回顾一下当前Go map的实现(Go 1.23.x)。 1. Go map的当前实现 map，也称为映射，或字典，或哈希表，是和数组等一样的最常见的数据结构。实现map有两个关键的考量，一个是哈希函数(hash function)，另一个就是碰撞处理(collision handling)。hash函数是数学家的事情，这里不表。对于碰撞处理，在大学数据结构课程中，老师通常会介绍两种常见的处理方案： 开放寻址法(Open Addressing) 在发生哈希碰撞时，尝试在哈希表中寻找下一个可用的位置，如下图所示k3与k1的哈希值发生碰撞后，算法会尝试从k1的位置开始向后找到一个空闲的位置： 链式哈希法(拉链法, Chaining) 每个哈希桶(bucket)存储一个链表（或其他数据结构），所有哈希值相同的元素(比如k1和k3)都被存储在该链表中。 Go当前的map实现采用的就是链式哈希，当然是经过优化过的了。要了解Go map的实现，关键把握住下面几点： 编译器重写 我们在用户层代码中使用的map操作都会被Go编译器重写为对应的runtime的map操作，就如下面Go团队成员Keith [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2024/11/14/go-map-use-swiss-table">本文永久链接</a> &#8211; https://tonybai.com/2024/11/14/go-map-use-swiss-table</p>
<p>在<a href="https://github.com/golang/go/issues/43930#issuecomment-2458068992">2024月11月5日的Go compiler and runtime meeting notes</a>中，我们注意到了一段重要内容，如下图红框所示：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-2.png" alt="" /></p>
<p>这表明，来自字节的一位工程师在两年多前提出的“<a href="https://github.com/golang/go/issues/54766">使用Swiss table重新实现Go map</a>”的建议即将落地，目前该issue已经被纳入<a href="https://github.com/golang/go/milestone/322">Go 1.24里程碑</a>。</p>
<p>Swiss Table是由Google工程师于2017年开发的一种高效哈希表实现，旨在优化内存使用和提升性能，解决Google内部代码库中广泛使用的std::unordered_map所面临的性能问题。<a href="https://www.youtube.com/watch?v=ncHmEUmJZf4">Google工程师Matt Kulukundis在2017年CppCon大会上详细介绍了他们在Swiss Table上的工作</a>：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-3.png" alt="" /></p>
<p>目前，Swiss Table已被应用于多种编程语言，包括<a href="https://abseil.io/about/design/swisstables">C++ Abseil库的flat_hash_map(可替换std::unordered_map)</a>、<a href="https://github.com/rust-lang/hashbrown">Rust标准库Hashmap的默认实现</a>等。</p>
<p>Swiss Table的出色表现是字节工程师提出这一问题的直接原因。字节跳动作为国内使用Go语言较为广泛的大厂。据issue描述，Go map的CPU消耗约占服务总体开销的4%。其中，map的插入（mapassign）和访问（mapaccess）操作的CPU消耗几乎是1:1。大家可千万不能小看4%这个数字，以字节、Google这样大厂的体量，减少1%也意味着真金白银的大幅节省。</p>
<p>Swiss Table被视为解决这一问题的潜在方案。字节工程师初版实现的基准测试结果显示，与原实现相比，Swiss Table在查询、插入和删除操作上均提升了20%至50%的性能，尤其是在处理大hashmap时表现尤为突出；迭代性能提升了10%；内存使用减少了0%至25%，并且不再消耗额外内存。</p>
<p>这些显著的性能提升引起了Go编译器和运行时团队的关注，特别是当时负责该子团队的Austin Clements。在经过两年多的实验和评估后，Go团队成员<a href="https://github.com/prattmic">Michael Pratt</a>基于Swiss Table实现的internal/runtime/maps最终成为Go map的底层默认实现。</p>
<p>在本文中，我们将简单介绍Swiss Table这一高效的哈希表实现算法，并提前看一下Go map的Swiss Table实现。</p>
<p>在进入swiss table工作原理介绍之前，我们先来回顾一下当前Go map的实现(Go 1.23.x)。</p>
<h2>1. Go map的当前实现</h2>
<p>map，也称为映射，或字典，或<a href="https://en.wikipedia.org/wiki/Hash_table">哈希表</a>，是和数组等一样的最常见的数据结构。实现map有两个关键的考量，一个是哈希函数(hash function)，另一个就是碰撞处理(collision handling)。hash函数是数学家的事情，这里不表。对于碰撞处理，在大学数据结构课程中，老师通常会介绍两种常见的处理方案：</p>
<ul>
<li>开放寻址法(Open Addressing)</li>
</ul>
<p>在发生哈希碰撞时，尝试在哈希表中寻找下一个可用的位置，如下图所示k3与k1的哈希值发生碰撞后，算法会尝试从k1的位置开始向后找到一个空闲的位置：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-4.png" alt="" /></p>
<ul>
<li>链式哈希法(拉链法, Chaining)</li>
</ul>
<p>每个哈希桶(bucket)存储一个链表（或其他数据结构），所有哈希值相同的元素(比如k1和k3)都被存储在该链表中。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-5.png" alt="" /></p>
<p>Go当前的map实现采用的就是链式哈希，当然是经过优化过的了。要了解Go map的实现，关键把握住下面几点：</p>
<ul>
<li>编译器重写</li>
</ul>
<p>我们在用户层代码中使用的map操作都会被Go编译器重写为对应的runtime的map操作，就如下面Go团队成员Keith Randall在GopherCon大会上讲解<a href="https://www.youtube.com/watch?v=Tl7mi9QmLns">map实现原理</a>的一个截图所示：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-6.png" alt="" /></p>
<ul>
<li>链式哈希</li>
</ul>
<p>前面提过，Go map当前采用的是链式哈希的实现，一个map在内存中的结构大致如下：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-7.png" alt="" /><br />
<center>来自Keith Randall的ppt截图</center></p>
<p>我们看到，一个map Header代表了一个map类型的实例，map header中存储了有关map的元数据(图中字段与当前实现可能有少许差异，毕竟那是几年前的一个片子了)，如：</p>
<pre><code>- len: 当前map中键值对的数量。
- bucket array: 存储数据的bucket数组，可以对比前面的链式哈希的原理图进行理解，不过不同的是，Go map中每个bucket本身就可以存储多个键值对，而不是指向一个键值对的链表。
- hash seed: 用于哈希计算的种子，用于分散数据并提高安全性。
</code></pre>
<p>通常一个bucket可以存储8个键值对，这些键值对是根据键的哈希值分配到对应的bucket中。</p>
<blockquote>
<p>注：在<a href="http://gk.link/a/10AVZ">《Go语言第一课》</a>专栏中，有关于Go map工作原理的系统说明，感兴趣的童鞋可以看看。</p>
</blockquote>
<ul>
<li>溢出桶(overflow bucket)</li>
</ul>
<p>每个bucket后面还会有Overflow Bucket。当一个bucket中的数据超出容量时，会创建overflow bucket来存储多余的数据。这样可以避免直接扩展bucket数组，节省内存空间。但如果出现过多的overflow bucket，性能就会下降。</p>
<ul>
<li>“蚂蚁搬家”式的扩容</li>
</ul>
<p>当map中出现过多overflow bucket而导致性能下降时，我们就要考虑map bucket扩容的事儿了，以始终保证map的操作性能在一个合理的范围。是否扩容由一个名为load factor的参数所控制。load factor是元素数量与bucket数量的比值，比值越高，map的读写性能越差。目前Go map采用了一个经验值来确定是否要扩容，即load factor = 6.5。当load factor超过这个值时，就会触发扩容。所谓扩容就是增大bucket数量(当前实现为增大一倍数量)，减少碰撞，让每个bucket中存放的element数量降下来。</p>
<p>扩容需要对存量element做rehash，在元素数量较多的情况下，“一次性”的完成桶的扩容会造成map操作延迟“突增”，无法满足一些业务场景的要求，因此Go map采用“增量”扩容的方式，即在访问和插入数据时，“蚂蚁搬家”式的做点搬移元素的操作，直到所有元素完成搬移。</p>
<p>Go map的当前实现应该可以适合大多数的场合，但依然有一些性能和延迟敏感的业务场景觉得<strong>Go map不够快</strong>，另外一个常被诟病的就是当前实现的桶扩容后就<a href="https://github.com/golang/go/issues/20135">不再缩容(shrink)了</a>，这会给内存带来压力。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-8.png" alt="" /><br />
<center>来自issue 20135的截图</center></p>
<p>下面我们再来看看swiss table的结构和工作原理。</p>
<h2>2. Swiss table的工作原理</h2>
<p>就像前面提到的，Swiss table并非来自某个大学或研究机构的论文，而是来自Google工程师在工程领域的”最佳实践”，因此关于Swiss table的主要资料都来自<a href="https://abseil.io/">Google的开源C++ library Abseil</a>以及<a href="https://www.youtube.com/watch?v=ncHmEUmJZf4">开发者的演讲视频</a>。在Abseil库中，它是flat_hash_map、flat_hash_set、node_hash_map以及node_hash_set等数据结构的底层实现，并且<a href="https://abseil.io/blog/20180927-swisstables">Swiss table的实现在2018年9月正式开源</a>。</p>
<p>和Go map当前实现不同，Swiss table使用的不是拉链法，而是开放寻址，但并非传统的方案。下面是根据公开资源画出的一个Swiss table的逻辑结构图(注意：并非真实内存布局)：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-9.png" alt="" /></p>
<p>如果用一个式子来表示Swiss table，我们可以用：</p>
<pre><code>A swiss table = N * (metdata array + slots array)
</code></pre>
<p>我们看到：swiss table将所谓的桶（这里叫slot）分为多个group，每个group中有16个slot，这也是swiss table的创新，即将开放寻址方法中的probing(探测key碰撞后下一个可用的位置(slot))放到一个16个slot的group中进行，这样的好处是可以通过一个<a href="https://tonybai.com/2024/07/21/simd-in-go">SIMD指令</a>并行探测16个slot，这种方法也被称为<strong>Group Probing</strong>。</p>
<p>在上图中，我们看到一个Group由metadata和16个slot组成。metadata中存储的是元数据，而slot中存储的是元素(key和value)。Group probling主要是基于metadata实现的，Google工程师的演讲有对group probing实现的细节描述。</p>
<p>当我们向swiss table插入一个元素或是查找一个元素时，swiss table会通过hash函数对key进行求值，结果是一个8字节(64bit)的数。和Go map的当前实现一样，这个哈希值的不同bit功用不同，下图是一个来自abseil官网的示例：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-10.png" alt="" /></p>
<p>哈希值的高57bit被称为H1，低7bit被称为H2。前者用于标识该元素在Group内的索引，查找和插入时都需要它。后者将被用于该元素的元数据，放在metadata中存储，用于快速的group probing之用，也被称为<strong>哈希指纹</strong>。</p>
<p>每个Group的metadata也是一个16字节数组，每个字节对应一个slot，是该slot的控制字节。这个字节的8个bit位的组成如下：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-12.png" alt="" /><br />
<center>图来自abseil库官网</center></p>
<p>metadata中的控制字节有三个状态：</p>
<ul>
<li>最高位为1，其余全零为<strong>空闲状态(Empty)</strong>，即对应的slot尚未曾被任何element占据过；</li>
<li>最高位为0，后7位为哈希指纹(H2)，为对应的slot当前已经有element占据的<strong>已使用状态</strong>；</li>
<li>最高位为1，其他位为1111110的，为对应的slot为<strong>已删除状态</strong>，后续可以被继续使用。</li>
</ul>
<p>下面是Abseil开发者演进slide中的一个针对swiss table的迭代逻辑：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-11.png" alt="" /></p>
<p>通过这幅图可以看出H1的作用。不过这里通过pos = pos + 1进行probing（探测）显然是不高效的！metadata之所以设计为如此，并保存了插入元素的哈希指纹就是为了实现高效的probing，下图演示了基于key的hash值的H2指纹通过SIMD指令从16个位置中快速得到匹配的pos的过程：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-13.png" alt="" /></p>
<p>虽然有两个匹配项，但这个过程就像“布隆过滤器”一样，快速排除了不可能的匹配项，减少了不必要的内存访问。</p>
<p>由此也可以看到：swiss table的16个条目的分组大小不是随意选择的，而是基于SSE2寄存器长度(128bit, 16bytes)和现代CPU的缓存行大小(64字节)优化的，保证了一个Group的控制字节能被单次SIMD指令处理。</p>
<p>此外swiss table也是通过load factor来判定是否需要对哈希表进行扩容，一旦扩容，swiss table通常是会将group数量增加一倍，然后重新计算当前所有元素在新groups中的新位置(rehash)，这个过程是有一定开销的。如果不做优化，当表中元素数量较多时，这个过程会导致操作延迟增加。</p>
<p>最后，虽然多数情况是在group内做probing，但当元素插入时，如果当前Group已满，就必须探测到下一个Group，并将元素插入到下一个Group。这样，在该元素的查找操作中，probing也会跨group进行。</p>
<p>到这里，我们已经粗略了解了swiss table的工作原理，那么Go tip对swiss table当前的实现又是怎样的呢？我们下面就来看看。</p>
<h2>3. Go tip版本当前的实现</h2>
<p>Go tip版本基于swiss table的实现在https://github.com/golang/go/blob/master/src/internal/runtime/maps下。</p>
<p>由于Go map是原生类型，且有了第一版实现，考虑到Go1兼容性，新版基于swiss table的实现也要继承已有的语义约束。同时，也要尽量避免swiss table自身的短板，Go团队在swiss table之上做了局部改进。比如为了将扩容带来的开销降到最低，Go引入了多table的设计，以支持渐进式扩容。也就是说一个map实际上是多个swiss table，而不是像上面说的一个map就是一个swiss table。每个table拥有自己的load factor，可以独立扩容(table的扩容是一次性扩容)，这样就可以<strong>将扩容的开销从全部数据变为局部少量数据，减少扩容带来的影响</strong>。</p>
<p>Go swiss-table based map的逻辑结构大致如下：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-map-use-swiss-table-14.png" alt="" /></p>
<p>我们可以看出与C++ swisstable的最直观不同之处除了有多个table外，每个group包含8个slot和一个control word，而不是16个slot。此外，Go使用了二次探测(quadratic probing), 探测序列必须以空slot结束。</p>
<p>为了实现渐进式扩容，数据分散在多个table中；单个table容量有上限(maxTableCapacity)，超过上限时分裂成两个table；使用可扩展哈希(extendible hashing)根据hash高位选择table，且每个table可以独立增长。</p>
<p>Go使用Directory管理多个table，Directory是Table的数组，大小为2^globalDepth。如果globalDepth=2，那Directory最多有4个表，分为0&#215;00、0&#215;01、0&#215;10、0&#215;11。Go通过key的hash值的前globalDepth个bit来选择table。这是一种“extendible hashing”，这是一种动态哈希技术，其核心特点是通过动态调整使用的哈希位数(比如上面提到的globalDepth)来实现渐进式扩容。比如：初始可能只用1位哈希值来区分，需要时可以扩展到用2位，再需要时可以扩展到用3位，以此类推。</p>
<p>举个例子，假设我们用二进制表示哈希值的高位，来看一个渐进式扩容的过程：</p>
<ul>
<li>初始状态 (Global Depth = 1):</li>
</ul>
<pre><code>directory
hash前缀  指向的table
0*** --&gt; table1 (Local Depth = 1)
1*** --&gt; table2 (Local Depth = 1)
</code></pre>
<ul>
<li>当table1满了需要分裂时，增加一位哈希值 (Global Depth = 2):</li>
</ul>
<pre><code>directory
hash前缀  指向的table
00** --&gt; table3 (Local Depth = 2)  // 由table1扩容而成
01** --&gt; table4 (Local Depth = 2)  // 由table1扩容而成
10** --&gt; table2 (Local Depth = 1)
11** --&gt; table2 (Local Depth = 1)  // 复用table2因为它的Local Depth还是1
</code></pre>
<ul>
<li>如果table2也满了，需要分裂：</li>
</ul>
<pre><code>directory
hash前缀  指向的table
00** --&gt; table3 (Local Depth = 2)
01** --&gt; table4 (Local Depth = 2)
10** --&gt; table5 (Local Depth = 2) // 由table2扩容而成
11** --&gt; table6 (Local Depth = 2) // 由table2扩容而成
</code></pre>
<p>通过extendible hashing实现的渐进式扩容，每次只处理一部分数据，扩容过程对其他操作影响小，空间利用更灵活。</p>
<p>对于新版go map实现而言，单个Table达到负载因子阈值时触发Table扩容。当需要分裂的Table的localDepth等于map的globalDepth时触发Directory扩容，这就好理解了。</p>
<p>除此之外，Go版本对small map也有特定优化，比如少量元素(&lt;=8)时直接使用单个group，避免或尽量降低swiss table天生在少量元素情况下的性能回退问题。</p>
<p>更多实现细节，大家可以自行阅读https://github.com/golang/go/blob/master/src/internal/runtime/maps/下的Go源码进行理解。</p>
<blockquote>
<p>注：目前swiss table版的go map依然还未最终定型，并且后续还会有各种优化加入，这里只是对当前的实现(2024.11.10)做概略介绍，不代表以后的map实现与上述思路完全一致。</p>
</blockquote>
<h2>4. Benchmark</h2>
<p>目前gotip版本中<a href="https://github.com/golang/go/commit/99d60c24e23d4d97ce51b1ee5660b60a5651693a">GOEXPERIMENT=swissmap默认已经打开</a>，我们直接用gotip版本即可体验基于swiss table实现的map。</p>
<p>字节工程师zhangyunhao的<a href="https://github.com/zhangyunhao116/gomapbench">gomapbench repo</a>提供了对map的性能基准测试代码，不过这个基准测试太多，我大幅简化了一下，只使用Int64，并只测试了元素个数分别为12、256和8192时的情况。</p>
<blockquote>
<p>注：我基于Centos 7.9，使用Go 1.23.0和gotip(devel go1.24-84e58c8 linux/amd64)跑的benchmark。</p>
</blockquote>
<pre><code>// 在experiments/swiss-table-map/mapbenchmark目录下
$go test -run='^$' -timeout=10h -bench=. -count=10 &gt; origin-map.txt
$GOEXPERIMENT=swissmap gotip test -run='^$' -timeout=10h -bench=. -count=10 &gt; swiss-table-map.txt
$benchstat origin-map.txt swiss-table-map.txt &gt; result.txt
</code></pre>
<blockquote>
<p>注：gotip版本的安装请参考<a href="http://gk.link/a/10AVZ">《Go语言第一课》</a>专栏的第3讲。benchstat安装命令为go install golang.org/x/perf/cmd/benchstat@latest</p>
</blockquote>
<p>下面是result.txt中的结果：</p>
<pre><code>goos: linux
goarch: amd64
pkg: demo
cpu: Intel(R) Xeon(R) Platinum
                                  │ origin-map.txt │         swiss-table-map.txt          │
                                  │     sec/op     │    sec/op     vs base                │
MapIter/Int/12-8                      179.7n ± 10%   190.6n ±  4%        ~ (p=0.436 n=10)
MapIter/Int/256-8                     4.328µ ±  5%   3.748µ ±  1%  -13.40% (p=0.000 n=10)
MapIter/Int/8192-8                    137.3µ ±  1%   123.6µ ±  1%   -9.95% (p=0.000 n=10)
MapAccessHit/Int64/12-8               10.12n ±  2%   10.68n ± 14%   +5.64% (p=0.000 n=10)
MapAccessHit/Int64/256-8              10.29n ±  3%   11.29n ±  1%   +9.77% (p=0.000 n=10)
MapAccessHit/Int64/8192-8             25.99n ±  1%   14.93n ±  1%  -42.57% (p=0.000 n=10)
MapAccessMiss/Int64/12-8              12.39n ± 88%   20.99n ± 50%        ~ (p=0.669 n=10)
MapAccessMiss/Int64/256-8             13.12n ±  6%   11.34n ±  7%  -13.56% (p=0.000 n=10)
MapAccessMiss/Int64/8192-8            15.71n ±  1%   14.03n ±  1%  -10.66% (p=0.000 n=10)
MapAssignGrow/Int64/12-8              607.1n ±  2%   622.6n ±  2%   +2.54% (p=0.000 n=10)
MapAssignGrow/Int64/256-8             25.98µ ±  3%   23.22µ ±  1%  -10.64% (p=0.000 n=10)
MapAssignGrow/Int64/8192-8            792.3µ ±  1%   844.1µ ±  1%   +6.54% (p=0.000 n=10)
MapAssignPreAllocate/Int64/12-8       450.2n ±  2%   409.2n ±  1%   -9.11% (p=0.000 n=10)
MapAssignPreAllocate/Int64/256-8     10.412µ ±  1%   6.055µ ±  2%  -41.84% (p=0.000 n=10)
MapAssignPreAllocate/Int64/8192-8     342.4µ ±  1%   232.6µ ±  2%  -32.05% (p=0.000 n=10)
MapAssignReuse/Int64/12-8             374.2n ±  1%   235.4n ±  2%  -37.07% (p=0.000 n=10)
MapAssignReuse/Int64/256-8            8.737µ ±  1%   4.716µ ±  4%  -46.03% (p=0.000 n=10)
MapAssignReuse/Int64/8192-8           296.4µ ±  1%   181.0µ ±  1%  -38.93% (p=0.000 n=10)
geomean                               1.159µ         984.2n        -15.11%
</code></pre>
<p>我们看到了除了少数测试项有不足外(比如MapAssignGrow以及一些元素数量少的情况下)，大多数测试项中，新版基于swiss table的map的性能都有大幅提升，有些甚至接近50%！</p>
<h2>5. 小结</h2>
<p>本文探讨了Go语言中的map实现的重塑，即引入Swiss Table这一高效哈希表结构的背景与优势。Swiss Table由Google工程师开发，旨在优化内存使用和提升性能，解决了传统哈希表在高负载情况下的性能瓶颈。通过对比现有的链式哈希实现，Swiss Table展示了在查询、插入和删除操作上显著提高的性能，尤其是在处理大规模数据时。</p>
<p>经过两年多的实验与评估，Go团队决定将Swiss Table作为Go map的底层实现，预计将在<a href="https://github.com/golang/go/milestone/322">Go 1.24</a>中正式落地。新的实现不仅承继了原有的语义约束，还通过引入多表和渐进式扩容的设计，进一步优化了扩容过程的性能。尽管当前实现仍在完善中，但Swiss Table的引入无疑为Go语言的性能提升提供了新的可能性，并为未来进一步优化奠定了基础。</p>
<p>对于那些因Go引入<a href="https://tonybai.com/2024/06/24/range-over-func-and-package-iter-in-go-1-23/">自定义iterator</a>而批评Go团队的Gopher来说，这个Go map的重塑无疑会很对他们的胃口。</p>
<p>本文涉及的源码可以在<a href="https://github.com/bigwhite/experiments/tree/master/swiss-table-map">这里</a>下载。</p>
<h2>6. 参考资料</h2>
<ul>
<li><a href="https://github.com/golang/go/issues/54766">runtime: use SwissTable</a> &#8211; https://github.com/golang/go/issues/54766</li>
<li><a href="https://gist.github.com/aclements/9fb32ac0a287d2ff360f1bc166cdf4b8">swiss table benchmark result</a> &#8211; https://gist.github.com/aclements/9fb32ac0a287d2ff360f1bc166cdf4b8</li>
<li><a href="https://faultlore.com/blah/hashbrown-tldr/">Swisstable, a Quick and Dirty Description</a> &#8211; https://faultlore.com/blah/hashbrown-tldr/</li>
<li><a href="https://abseil.io/about/design/swisstables">Swiss Tables Design Notes</a> &#8211; https://abseil.io/about/design/swisstables</li>
<li><a href="https://www.youtube.com/watch?v=ncHmEUmJZf4">Designing a Fast, Efficient, Cache-friendly Hash Table, Step by Step</a> &#8211; https://www.youtube.com/watch?v=ncHmEUmJZf4</li>
<li><a href="https://www.youtube.com/watch?v=JZE3_0qvrMg">Abseil&#8217;s Open Source Hashtables: 2 Years In</a> &#8211; https://www.youtube.com/watch?v=JZE3_0qvrMg</li>
<li><a href="https://abseil.io/blog/20180927-swisstables">Swiss Tables and absl::Hash</a> &#8211; https://abseil.io/blog/20180927-swisstables</li>
<li><a href="https://www.dolthub.com/blog/2023-03-28-swiss-map/">SwissMap: A smaller, faster Golang Hash Table</a> &#8211; https://www.dolthub.com/blog/2023-03-28-swiss-map/</li>
<li><a href="https://www.freecodecamp.org/news/what-is-a-hash-map/">What is a Hash Map?</a> &#8211; https://www.freecodecamp.org/news/what-is-a-hash-map/</li>
<li><a href="https://www.youtube.com/watch?v=Tl7mi9QmLns">Inside the Map Implementation</a> &#8211; https://www.youtube.com/watch?v=Tl7mi9QmLns</li>
</ul>
<hr />
<p><a href="https://public.zsxq.com/groups/51284458844544">Gopher部落知识星球</a>在2024年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。同时，我们也会加强代码质量和最佳实践的分享，包括如何编写简洁、可读、可测试的Go代码。此外，我们还会加强星友之间的交流和互动。欢迎大家踊跃提问，分享心得，讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落，享受coding的快乐! 欢迎大家踊跃加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-tribe-zsxq-small-card.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/go-programming-from-beginner-to-master-qr.png" alt="img{512x368}" /></p>
<p><img src="http://image.tonybai.com/img/tonybai/go-first-course-banner.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/imooc-go-column-pgo-with-qr.jpg" alt="img{512x368}" /></p>
<p>著名云主机服务厂商DigitalOcean发布最新的主机计划，入门级Droplet配置升级为：1 core CPU、1G内存、25G高速SSD，价格5$/月。有使用DigitalOcean需求的朋友，可以打开这个<a href="https://m.do.co/c/bff6eed92687">链接地址</a>：https://m.do.co/c/bff6eed92687 开启你的DO主机之路。</p>
<p>Gopher Daily(Gopher每日新闻) &#8211; https://gopherdaily.tonybai.com</p>
<p>我的联系方式：</p>
<ul>
<li>微博(暂不可用)：https://weibo.com/bigwhite20xx</li>
<li>微博2：https://weibo.com/u/6484441286</li>
<li>博客：tonybai.com</li>
<li>github: https://github.com/bigwhite</li>
<li>Gopher Daily归档 &#8211; https://github.com/bigwhite/gopherdaily</li>
<li>Gopher Daily Feed订阅 &#8211; https://gopherdaily.tonybai.com/feed</li>
</ul>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。</p>
<p style='text-align:left'>&copy; 2024, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2024/11/14/go-map-use-swiss-table/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Go团队的工作方式</title>
		<link>https://tonybai.com/2024/06/22/how-things-get-done-on-the-go-team/</link>
		<comments>https://tonybai.com/2024/06/22/how-things-get-done-on-the-go-team/#comments</comments>
		<pubDate>Fri, 21 Jun 2024 23:07:26 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[CameronBalahan]]></category>
		<category><![CDATA[Context]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[go1.23]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[GoogleIO]]></category>
		<category><![CDATA[GopherCon]]></category>
		<category><![CDATA[gopls]]></category>
		<category><![CDATA[GoProposalProcess]]></category>
		<category><![CDATA[GoReleaseCycle]]></category>
		<category><![CDATA[GoTime]]></category>
		<category><![CDATA[GoWiki]]></category>
		<category><![CDATA[IDE]]></category>
		<category><![CDATA[issue]]></category>
		<category><![CDATA[KenThompson]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[LLM]]></category>
		<category><![CDATA[RobertGriesemer]]></category>
		<category><![CDATA[RobPike]]></category>
		<category><![CDATA[RussCox]]></category>
		<category><![CDATA[SameerAjmari]]></category>
		<category><![CDATA[SBOM]]></category>
		<category><![CDATA[slack]]></category>
		<category><![CDATA[Telemetry]]></category>
		<category><![CDATA[vscode]]></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=4202</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2024/06/22/how-things-get-done-on-the-go-team 在Go 1.23版本即将发布(2024.8)之前，在GopherCon 2024开幕(2024.7)之前，Go团队成员Cameron Balahan(Go产品负责人)、 Sameer Ajmani（Go团队工程总监）和Russ Cox（Go团队技术负责人）参加了业界知名的播客栏目GoTime的最新一期活动，主题是“How things get done on the Go Team”。在这期活动中，Go团队这三个leader分享了Go团队的工作方式，包括：Go团队的组成、现状与职责划分、与社区互动、决策与规划流程、产品管理等方面。这里基于这期播客的脚本提炼了其中主要的观点，贴到这里供大家参考。 1. Go团队组成及职责划分 Go团队从2007年诞生，至今已经有17年了。最初的Go团队由罗伯·派克(Rob Pike)、罗伯特·格瑞史莫(Robert Griesemer)和肯·汤普森（Ken Thompson）三个Go语言之父组成。之后Russ Cox和Ian Lance Taylor加入团队，形成了Go团队最核心的五人组。 Sameer Ajmani在Go 1.0发布前后加入，当时团队有10几个人，我们熟悉的context包就是由他和Russ Cox一起设计并实现的。 Cameron Balahan在4年前加入Go团队，他也是今年在Google I/O大会上做“Go是一个平台”演讲的Go团队成员。 目前Google内部组织调整后，Go团队划归Google云团队管理，但其工作相对独立。 现在，Go团队由不同小组组成，主要包括三个小组：核心组、工具组和安全组。核心组负责编译器、运行时、链接器以及核心发布流程。工具组负责构建系统、Go命令、Go VSCode IDE插件以及gopls语言服务器等。安全组则专注于Go的供应链安全性、漏洞扫描和修复等方面。 尽管划分了不同的小组，但Go团队在日常工作中感觉就像是一个整体，各小组之间合作紧密。特定任务往往需要几个小组共同参与，例如漏洞检测与修复功能的开发就涉及了核心组、工具组和安全组的工作。 Go团队的工作由核心成员和开源社区两部分组成。核心成员负责构建整体框架与关键功能，而开源社区则为Go语言贡献众多细节上的改进和完善。两者紧密互动，形成良性循环。 2. Go团队与Go社区的互动 Go社区对语言发展做出了重大贡献，因此Go团队始终采取非常积极开放的态度与社区互动。包括但不限于使用Slack、邮件列表、Issue跟踪、Go博客等多种渠道倾听Go社区声音，接纳Go社区贡献。任何人都可以参与讨论并提出建议。 目前较为正式的决策途径是“Go提案流程(Proposal Process)”。任何人都可以在这一平台上提出建议，供Go团队和全体社区评议。不论大小，只要通过审议，这些建议都可能被纳入语言或生态系统的未来发展规划。 除了直接参与讨论和决策外，Go社区还可以通过编写代码、发现并报告漏洞等方式为Go语言做贡献。Go团队会将高质量的外部代码整合进官方发行版。 3. 决策与规划流程 Go团队在做决策时，会优先考虑目标的一致性和充分的信息共享（比如公开利用Go遥测工具采集的数据）。如果出现分歧，通常是由于目标不一致或信息不对称(以类型别名加入Go的过程为例)造成的。因此，团队会先明确共同目标，并确保每个人掌握了相同的信息，然后再做出决策。 在规划过程中，Go团队首先要考虑Go语言既定的目标，即能够同时处理”生产规模化”(大量机器与海量数据)和”人力规模化”(大型项目与众多贡献者)。任何需要持续10年以上的重大决策，都必须符合这两个目标。 从长远来看，安全性与开源软件的可持续发展是Go团队需要重点关注的问题。他们将积极主导新标准与新模式，以提高整个行业的供应链安全性水平。 功能规划上，Go团队会同时考虑Go用户/社区和Google内部需求：Go用户和Go社区从Go中寻找价值，比如高生产力、高性能、高可靠和高安全；Google要确保其内部系统运行良好，开发人员满意，其系统可靠，安全，诸如此类。当然，Google也希望外部Go开发人员也这样做。同时，Google也希望那些外部的Go开发人员获得成功和快乐。为此，Go团队会寻求双赢解决方案。比如兼容性工作就是为了满足Kubernetes等重要系统的需求(IP地址解析)。在新特性开发过程中，Go团队会确保功能在整个生态链上保持一致性。 在发布规划上，Go团队需要考虑两个周期，一个是Go团队公开的Go版本发布周期，主版本一年两次。同时，Go团队leader还要考虑内部Google的规划周期，往往有一个年度计划周期，Go团队在其中执行 OKR、目标和关键结果。 4. 产品管理与Go的未来展望 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/how-things-get-done-on-the-go-team-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2024/06/22/how-things-get-done-on-the-go-team">本文永久链接</a> &#8211; https://tonybai.com/2024/06/22/how-things-get-done-on-the-go-team</p>
<p>在<a href="https://tonybai.com/2024/05/30/go-1-23-foresight/">Go 1.23版本</a>即将发布(2024.8)之前，在<a href="https://www.gophercon.com/">GopherCon 2024</a>开幕(2024.7)之前，Go团队成员<a href="https://tonybai.com/2024/05/19/what-the-go-team-think-go-is/">Cameron Balahan(Go产品负责人)</a>、 Sameer Ajmani（Go团队工程总监）和<a href="https://swtch.com/~rsc/">Russ Cox（Go团队技术负责人）</a>参加了业界知名的播客栏目<a href="https://changelog.com/gotime">GoTime</a>的最新一期活动，主题是<a href="https://changelog.com/gotime/318">“How things get done on the Go Team”</a>。在这期活动中，Go团队这三个leader分享了Go团队的工作方式，包括：Go团队的组成、现状与职责划分、与社区互动、决策与规划流程、产品管理等方面。这里基于<a href="https://github.com/thechangelog/transcripts/blob/master/gotime/go-time-318.md">这期播客的脚本</a>提炼了其中主要的观点，贴到这里供大家参考。</p>
<h2>1. Go团队组成及职责划分</h2>
<p>Go团队从2007年诞生，至今已经有17年了。最初的Go团队由罗伯·派克(Rob Pike)、罗伯特·格瑞史莫(Robert Griesemer)和肯·汤普森（Ken Thompson）三个Go语言之父组成。之后Russ Cox和Ian Lance Taylor加入团队，形成了Go团队最核心的五人组。</p>
<p>Sameer Ajmani在Go 1.0发布前后加入，当时团队有10几个人，我们熟悉的<a href="https://tonybai.com/2022/11/08/understand-go-context-by-example">context包</a>就是由他和Russ Cox一起设计并实现的。</p>
<p>Cameron Balahan在4年前加入Go团队，他也是今年在Google I/O大会上做“<a href="https://tonybai.com/2024/05/19/what-the-go-team-think-go-is">Go是一个平台</a>”演讲的Go团队成员。</p>
<p>目前Google内部组织调整后，Go团队划归Google云团队管理，但其工作相对独立。 现在，Go团队由不同小组组成，主要包括三个小组：核心组、工具组和安全组。核心组负责编译器、运行时、链接器以及核心发布流程。工具组负责构建系统、Go命令、<a href="https://code.visualstudio.com/docs/languages/go">Go VSCode IDE插件</a>以及<a href="https://github.com/golang/tools/tree/master/gopls">gopls语言服务器</a>等。安全组则专注于<a href="https://tonybai.com/2022/03/14/software-supply-chain-security-in-go">Go的供应链安全性</a>、<a href="https://tonybai.com/2022/09/10/an-intro-of-govulncheck">漏洞扫描和修复</a>等方面。</p>
<p>尽管划分了不同的小组，但Go团队在日常工作中感觉就像是一个整体，各小组之间合作紧密。特定任务往往需要几个小组共同参与，例如漏洞检测与修复功能的开发就涉及了核心组、工具组和安全组的工作。</p>
<p>Go团队的工作由核心成员和开源社区两部分组成。核心成员负责构建整体框架与关键功能，而开源社区则为Go语言贡献众多细节上的改进和完善。两者紧密互动，形成良性循环。</p>
<h2>2. Go团队与Go社区的互动</h2>
<p>Go社区对语言发展做出了重大贡献，因此Go团队始终采取非常积极开放的态度与社区互动。包括但不限于使用Slack、邮件列表、Issue跟踪、Go博客等多种渠道倾听Go社区声音，接纳Go社区贡献。任何人都可以参与讨论并提出建议。</p>
<p>目前较为正式的决策途径是“<a href="https://github.com/golang/proposal#the-proposal-process">Go提案流程(Proposal Process)</a>”。任何人都可以在这一平台上提出建议，供Go团队和全体社区评议。不论大小，只要通过审议，这些建议都可能被纳入语言或生态系统的未来发展规划。</p>
<p>除了直接参与讨论和决策外，Go社区还可以通过编写代码、发现并报告漏洞等方式为Go语言做贡献。Go团队会将高质量的外部代码整合进官方发行版。</p>
<h2>3. 决策与规划流程</h2>
<p>Go团队在做决策时，会优先考虑<a href="https://tonybai.com/2023/12/10/go-changes/">目标的一致性</a>和充分的信息共享（比如公开利用<a href="https://telemetry.go.dev/">Go遥测工具</a>采集的数据）。如果出现分歧，通常是由于目标不一致或信息不对称(<a href="https://github.com/golang/go/issues/18130">以类型别名加入Go的过程为例</a>)造成的。因此，团队会先明确共同目标，并确保每个人掌握了相同的信息，然后再做出决策。</p>
<p>在规划过程中，Go团队首先要考虑Go语言既定的目标，即能够同时处理”生产规模化”(大量机器与海量数据)和”人力规模化”(大型项目与众多贡献者)。任何需要持续10年以上的重大决策，都必须符合这两个目标。</p>
<p>从长远来看，安全性与开源软件的可持续发展是Go团队需要重点关注的问题。他们将积极主导新标准与新模式，以提高整个行业的供应链安全性水平。</p>
<p>功能规划上，Go团队会同时考虑Go用户/社区和Google内部需求：Go用户和Go社区从Go中寻找价值，比如高生产力、高性能、高可靠和高安全；Google要确保其内部系统运行良好，开发人员满意，其系统可靠，安全，诸如此类。当然，Google也希望外部Go开发人员也这样做。同时，Google也希望那些外部的Go开发人员获得成功和快乐。为此，Go团队会寻求双赢解决方案。比如兼容性工作就是为了满足Kubernetes等重要系统的需求(IP地址解析)。在新特性开发过程中，Go团队会确保功能在整个生态链上保持一致性。</p>
<p>在发布规划上，Go团队需要考虑两个周期，一个是Go团队公开的<a href="https://go.dev/wiki/Go-Release-Cycle">Go版本发布周期</a>，主版本一年两次。同时，Go团队leader还要考虑内部Google的规划周期，往往有一个年度计划周期，Go团队在其中执行 OKR、目标和关键结果。</p>
<h2>4. 产品管理与Go的未来展望</h2>
<p>作为Go产品负责人，CAMERON BALAHAN认为他会从优先级路线图、愿景角度以及Go团队为用户/社区和Google提供的价值的角度来弄清楚Go是什么，他认为Go是用于开发生产级软件的高效平台。作为编程语言，Go语言的产品管理理念就是构建一个高效且稳定的平台，支撑”生产级软件的高效开发”。</p>
<p>Go在解决云问题方面非常成功。云的大部分基础设施都是用Go编写的，并且Go在这方面做得很好，具有独特优势。Go团队希望Go在这一领域能够提供持续性的方案并取得持续性的成功，这决定了Go团队关注两个核心要素：生产效率和软件质量，这其中包括可靠性、安全性等重要的要素。</p>
<p>此外，Sameer认为人工智能的发展也为Go带来了新的机遇，随着越来越多的大公司、企业和初创公司希望在人工智能模型之上构建系统，而如何使Go成为构建智能基础设施以及基于大模型构建生产级、值得信赖、可靠的AI应用系统的语言，是下一个重要的前沿领域，Go团队将看到对此的大量需求，并认为Go是一个非常合适的选择。Go团队也在拭目以待！</p>
<p>编程语言的采用是一个缓慢的过程。Go语言目前已经到了一个关键的增长点，有望在新兴计算领域(AI)获得更广泛的使用。团队需要持续关注新的计算范式，及时调整以满足新需求。</p>
<p>Go社区对该语言的热爱是Go发展的重要动力。整个Go社区都是建立在Go之上的。Go团队本身无法建造所有东西，Go团队只要确保Go用户能够使用Go构建他们需要构建的东西，积极赋能社区发挥创造力，丰富Go的生态系统，才能继续让Go保持在人们需要的那种前沿，以便建立他们的业务、构建软件、构建他们需要的东西，生产级的高效、安全与可靠。</p>
<h2>5. 不受欢迎的观点(GoTime常设环节)</h2>
<ul>
<li>Sameer：context is fine。</li>
<li>Cameron：I really like Go’s error handling.</li>
<li>Russ：null pointers are fine. They’re kind of a fundamental fact of computers, is that memory can be zeroed.</li>
</ul>
<hr />
<p><a href="https://public.zsxq.com/groups/51284458844544">Gopher部落知识星球</a>在2024年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。同时，我们也会加强代码质量和最佳实践的分享，包括如何编写简洁、可读、可测试的Go代码。此外，我们还会加强星友之间的交流和互动。欢迎大家踊跃提问，分享心得，讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落，享受coding的快乐! 欢迎大家踊跃加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-tribe-zsxq-small-card.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/go-programming-from-beginner-to-master-qr.png" alt="img{512x368}" /></p>
<p><img src="http://image.tonybai.com/img/tonybai/go-first-course-banner.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/imooc-go-column-pgo-with-qr.jpg" alt="img{512x368}" /></p>
<p>著名云主机服务厂商DigitalOcean发布最新的主机计划，入门级Droplet配置升级为：1 core CPU、1G内存、25G高速SSD，价格5$/月。有使用DigitalOcean需求的朋友，可以打开这个<a href="https://m.do.co/c/bff6eed92687">链接地址</a>：https://m.do.co/c/bff6eed92687 开启你的DO主机之路。</p>
<p>Gopher Daily(Gopher每日新闻) &#8211; https://gopherdaily.tonybai.com</p>
<p>我的联系方式：</p>
<ul>
<li>微博(暂不可用)：https://weibo.com/bigwhite20xx</li>
<li>微博2：https://weibo.com/u/6484441286</li>
<li>博客：tonybai.com</li>
<li>github: https://github.com/bigwhite</li>
<li>Gopher Daily归档 &#8211; https://github.com/bigwhite/gopherdaily</li>
</ul>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。</p>
<p style='text-align:left'>&copy; 2024, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2024/06/22/how-things-get-done-on-the-go-team/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Go早期的那些布道者</title>
		<link>https://tonybai.com/2024/05/17/the-early-evangelists-of-go/</link>
		<comments>https://tonybai.com/2024/05/17/the-early-evangelists-of-go/#comments</comments>
		<pubDate>Fri, 17 May 2024 13:43:39 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AndrewGerrand]]></category>
		<category><![CDATA[Apple]]></category>
		<category><![CDATA[Ardan]]></category>
		<category><![CDATA[badger]]></category>
		<category><![CDATA[BillKennedy]]></category>
		<category><![CDATA[BradFitzpatrick]]></category>
		<category><![CDATA[BrianKetelsen]]></category>
		<category><![CDATA[cobra]]></category>
		<category><![CDATA[Context]]></category>
		<category><![CDATA[DaveCheney]]></category>
		<category><![CDATA[deps.dev]]></category>
		<category><![CDATA[Dgraph]]></category>
		<category><![CDATA[DmitryVyukov]]></category>
		<category><![CDATA[FrancescCampoy]]></category>
		<category><![CDATA[fuzzing]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[go-fuzz]]></category>
		<category><![CDATA[go-nuts]]></category>
		<category><![CDATA[go.mod]]></category>
		<category><![CDATA[go1.18]]></category>
		<category><![CDATA[go1.23]]></category>
		<category><![CDATA[GoCourse]]></category>
		<category><![CDATA[GoExecutionTracer]]></category>
		<category><![CDATA[gohugo]]></category>
		<category><![CDATA[GoInAction]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[gomodule]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Gopher]]></category>
		<category><![CDATA[gopherchina]]></category>
		<category><![CDATA[GopherCon]]></category>
		<category><![CDATA[GoProgrammingBlueprints]]></category>
		<category><![CDATA[gops]]></category>
		<category><![CDATA[goroutine]]></category>
		<category><![CDATA[GoTime]]></category>
		<category><![CDATA[govanityurls]]></category>
		<category><![CDATA[Go社区]]></category>
		<category><![CDATA[grafana]]></category>
		<category><![CDATA[hey]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[hugo]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[JaanaDogan]]></category>
		<category><![CDATA[JustForFunc]]></category>
		<category><![CDATA[KenThompson]]></category>
		<category><![CDATA[LiveJournal]]></category>
		<category><![CDATA[MatRyer]]></category>
		<category><![CDATA[Memcached]]></category>
		<category><![CDATA[NUMA]]></category>
		<category><![CDATA[pprof]]></category>
		<category><![CDATA[Rakyll]]></category>
		<category><![CDATA[RobertGriesemer]]></category>
		<category><![CDATA[RobPike]]></category>
		<category><![CDATA[RussCox]]></category>
		<category><![CDATA[spf13]]></category>
		<category><![CDATA[statik]]></category>
		<category><![CDATA[SteveFrancia]]></category>
		<category><![CDATA[tailscale]]></category>
		<category><![CDATA[UltimateGo]]></category>
		<category><![CDATA[unique]]></category>
		<category><![CDATA[upspin]]></category>
		<category><![CDATA[vendor]]></category>
		<category><![CDATA[viper]]></category>
		<category><![CDATA[WireGurad]]></category>
		<category><![CDATA[workshop]]></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=4168</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2024/05/17/the-early-evangelists-of-go Go自2009年开源至今已经快15年了！这期间，有很多人对Go语言的发展做出了重要贡献，起到了至关重要的作用，他们被视为Go语言的早期布道者和鼓吹者。他们向Go社区传达着Go的价值观、Go的最新发展、Go的使用方法以及最佳实践。 这些人有来自Go团队的，有来自Google但非Go团队的，也有Go的早期采纳者和贡献者。如今这些人的状况不尽相同。有些人依然在活跃在Go团队中，为Go的演进持续做着贡献；有些人由于各种原因，已经退居二线，但仍心系Go的发展；还有一些人则逐渐淡出Go社区，或者说不再复当年的那种热忱。 不过，无论哪种，这些人为Go语言的推广和发展都做出了不可磨灭的贡献，值得Gopher们铭记。在这篇文章中，我就来说说这些Go早期的布道师。也可以让后进入Go阵营的Gopher们了解一下过去的事情。 注：这里是不完全统计，还有很多早期Go布道师做出了重要贡献，限于篇幅，这里就不一一列举细数了。 Rob Pike Rob Pike 是Go语言的共同创始人之一，他在2007年与Ken Thompson和Robert Griesemer一起开始了Go语言的开发。 作为一名经验丰富的计算机科学家，Rob Pike曾在贝尔实验室工作，参与了Plan 9和Inferno操作系统的开发，UTF-8也是他的杰作。此外，他还是C语言和UNIX操作系统的早期贡献者之一。 Rob Pike为Go语言的设计和实现做出了重大贡献。他的设计理念强调简洁、并发和高效，这些理念深深影响了Go语言的核心特性。在Go语言的早期发展阶段，Rob Pike几乎主导了Go语言规范的制定，并负责了许多关键语言特性的开发。在Ken Thompson退休后，他成为了Go语言第一代的领军人物。 除了技术贡献，Rob Pike还是最为积极的Go语言推广者。他在Google内外的各种会议和技术活动中发表演讲，介绍Go语言的优势、应用场景以及使用方法。他的演讲风格生动有趣，深受开发者的喜爱。此外，Rob Pike还撰写了大量关于Go语言的博客和技术文档，为社区提供了宝贵的学习资源。 截图来自golang.design 他的“3 Day Go Course”也是最早、最权威的Go教程，即便在今天看来略有些Outdated了:)。 注：关于Rob Pike的早期3-days Go Course ppt，可以在这里下载https://www.cs.cmu.edu/afs/cs.cmu.edu/academic/class/15440-f11/go/doc/ 现如今，Rob Pike已经从Google退休了，并长居澳大利亚，并继续为Go语言的发展做着贡献。尽管他不再像早期那样频繁地参与社区活动，但他的影响力依然深远，Go 1.18泛型发布前，Rob Pike就及时纠正了Go团队对泛型的支持策略。 Rob Pike的工作为Go语言奠定了坚实的基础，使其成为现代编程语言中的一颗璀璨明珠。 Robert Griesemer Robert Griesemer是Go语言的另一位共同创始人。他在加入Go团队之前，他曾参与Google V8 JavaScript引擎、Sawzall语言、Java HotSpot虚拟机和Strongtalk系统的工作，拥有丰富的编程语言设计和实现经验。 Griesemer在设计和实现Go语言方面发挥了关键作用，尤其是在语法和编译器的开发上。Griesemer的设计理念强调语言的简洁性和易用性，这使得Go语言在开发者中迅速获得了广泛的认可。他致力于优化编译器性能，使Go程序能够高效地运行在各种平台上。Griesemer还参与了Go语言标准库的设计和实现，为开发者提供了丰富的工具和资源。 在Go语言的推广方面，Griesemer同样不遗余力。他经常参与技术会议和社区活动，分享Go语言的设计理念和最佳实践，他也是唯一在GopherChina上现场进行分享的Go语言之父。 他的技术讲座深入浅出，帮助许多开发者快速上手Go语言。此外，Griesemer还与其他团队成员合作撰写了多篇技术论文和博客，进一步推动了Go语言的普及。 截图来自golang.design 目前，Griesemer依然在Google Go团队工作，奋战在Go语言的开发和优化的第一线。他和Ian Lance Taylor共同设计和实现了Go泛型机制，大幅提升了Go的表达能力。他的工作对Go语言的成功起到了至关重要的作用，使其成为许多大型项目和企业的首选开发语言。 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2024/05/17/the-early-evangelists-of-go">本文永久链接</a> &#8211; https://tonybai.com/2024/05/17/the-early-evangelists-of-go</p>
<p>Go自2009年开源至今<a href="https://tonybai.com/2023/11/11/go-opensource-14-years/">已经快15年了</a>！这期间，有很多人对Go语言的发展做出了重要贡献，起到了至关重要的作用，他们被视为<strong>Go语言的早期布道者和鼓吹者</strong>。他们向Go社区传达着Go的价值观、Go的最新发展、Go的使用方法以及最佳实践。</p>
<p>这些人有来自Go团队的，有来自Google但非Go团队的，也有Go的早期采纳者和贡献者。如今这些人的状况不尽相同。有些人依然在活跃在Go团队中，为Go的演进持续做着贡献；有些人由于各种原因，已经退居二线，但仍心系Go的发展；还有一些人则逐渐淡出Go社区，或者说不再复当年的那种热忱。</p>
<p>不过，无论哪种，这些人为Go语言的推广和发展都做出了不可磨灭的贡献，值得Gopher们铭记。在这篇文章中，我就来说说这些Go早期的布道师。也可以让后进入Go阵营的Gopher们了解一下过去的事情。</p>
<blockquote>
<p>注：这里是不完全统计，还有很多早期Go布道师做出了重要贡献，限于篇幅，这里就不一一列举细数了。</p>
</blockquote>
<h2><a href="https://en.wikipedia.org/wiki/Rob_Pike">Rob Pike</a></h2>
<p>Rob Pike 是Go语言的共同创始人之一，他在2007年与Ken Thompson和Robert Griesemer一起开始了Go语言的开发。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-2.jpeg" alt="" /></p>
<p>作为一名经验丰富的计算机科学家，Rob Pike曾在贝尔实验室工作，参与了Plan 9和Inferno操作系统的开发，UTF-8也是他的杰作。此外，他还是C语言和UNIX操作系统的早期贡献者之一。</p>
<p>Rob Pike为Go语言的设计和实现做出了重大贡献。他的设计理念<a href="https://time.geekbang.org/column/article/426740">强调简洁、并发和高效</a>，这些理念深深影响了Go语言的核心特性。在Go语言的早期发展阶段，Rob Pike几乎主导了Go语言规范的制定，并负责了许多关键语言特性的开发。在Ken Thompson退休后，他成为了Go语言第一代的领军人物。</p>
<p>除了技术贡献，Rob Pike还是<strong>最为积极的Go语言推广者</strong>。他在Google内外的各种会议和技术活动中发表演讲，介绍Go语言的优势、应用场景以及使用方法。他的演讲风格生动有趣，深受开发者的喜爱。此外，Rob Pike还撰写了大量关于Go语言的博客和技术文档，为社区提供了宝贵的学习资源。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-3.png" alt="" /><br />
<center>截图来自golang.design</center></p>
<p>他的<a href="https://tonybai.com/2012/08/23/the-go-programming-language-tutorial-part1/">“3 Day Go Course”</a>也是最早、最权威的Go教程，即便在今天看来略有些Outdated了:)。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-5.png" alt="" /></p>
<blockquote>
<p>注：关于Rob Pike的早期<a href="https://www.cs.cmu.edu/afs/cs.cmu.edu/academic/class/15440-f11/go/doc/">3-days Go Course ppt</a>，可以在这里下载https://www.cs.cmu.edu/afs/cs.cmu.edu/academic/class/15440-f11/go/doc/</p>
</blockquote>
<p>现如今，Rob Pike已经从Google退休了，并长居澳大利亚，并继续为Go语言的发展做着贡献。尽管他不再像早期那样频繁地<a href="https://tonybai.com/2024/01/07/what-we-got-right-what-we-got-wrong/">参与社区活动</a>，但他的影响力依然深远，<a href="https://tonybai.com/2022/04/20/some-changes-in-go-1-18">Go 1.18泛型</a>发布前，<a href="https://tonybai.com/2021/10/28/expectations-for-generics-in-go-1.18">Rob Pike就及时纠正了Go团队对泛型的支持策略</a>。</p>
<p>Rob Pike的工作为Go语言奠定了坚实的基础，使其成为现代编程语言中的一颗璀璨明珠。</p>
<h2><a href="https://en.wikipedia.org/wiki/Robert_Griesemer">Robert Griesemer</a></h2>
<p>Robert Griesemer是Go语言的另一位共同创始人。他在加入Go团队之前，他曾参与Google V8 JavaScript引擎、Sawzall语言、Java HotSpot虚拟机和Strongtalk系统的工作，拥有丰富的编程语言设计和实现经验。</p>
<p>Griesemer在设计和实现Go语言方面发挥了关键作用，尤其是在语法和编译器的开发上。Griesemer的设计理念强调语言的简洁性和易用性，这使得Go语言在开发者中迅速获得了广泛的认可。他致力于优化编译器性能，使Go程序能够高效地运行在各种平台上。Griesemer还参与了Go语言标准库的设计和实现，为开发者提供了丰富的工具和资源。</p>
<p>在Go语言的推广方面，Griesemer同样不遗余力。他经常参与技术会议和社区活动，分享Go语言的设计理念和最佳实践，他也是唯一在GopherChina上现场进行分享的Go语言之父。</p>
<p>他的技术讲座深入浅出，帮助许多开发者快速上手Go语言。此外，Griesemer还与其他团队成员合作撰写了多篇<a href="https://tonybai.com/2022/05/04/the-paper-of-go-programming-language-and-environment">技术论文和博客</a>，进一步推动了Go语言的普及。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-4.png" alt="" /><br />
<center>截图来自golang.design</center></p>
<p>目前，Griesemer依然在Google Go团队工作，奋战在Go语言的开发和优化的第一线。他和<a href="https://github.com/ianlancetaylor">Ian Lance Taylor</a>共同设计和实现了<a href="https://tonybai.com/2021/02/18/typing-generic-go-by-griesemer-at-gophercon-2020/">Go泛型机制</a>，大幅提升了Go的表达能力。他的工作对Go语言的成功起到了至关重要的作用，使其成为许多大型项目和企业的首选开发语言。</p>
<h2><a href="https://en.wikipedia.org/wiki/Brad_Fitzpatrick">Brad Fitzpatrick</a></h2>
<p>Brad Fitzpatrick是一位资深的美国程序员。在加入Go团队之前，Fitzpatrick就因创建LiveJournal和Memcached而闻名。后来加入Google，成为Go团队的重要成员，并在Go语言社区中拥有很高的声誉。</p>
<p>在Go语言的发展过程中，Fitzpatrick为许多关键组件做出了贡献，尤其是在网络库和并发编程模型方面。他创建了诸如HTTP包和<a href="https://github.com/golang/go/issues/14660">context包</a>等核心库，这些库广泛应用于Go语言的网络编程中。</p>
<p>Fitzpatrick不仅在技术上对Go做出了杰出贡献，他还是Go社区活动的积极参与者，是Go团队中参与社区活动的“典范”。他经常在技术会议和用户组活动中发表演讲，分享自己的经验和最佳实践。Fitzpatrick的工作帮助许多开发者更好地理解和使用Go语言，推动了社区的发展。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-6.png" alt="" /><br />
<center>截图来自golang.design</center></p>
<p>几年前，Fitzpatrick离开了Google并重新创业，他联创的<a href="https://github.com/tailscale">Tailscale</a>基于<a href="https://tonybai.com/2020/03/29/hello-wireguard/">WireGuard</a>和Go打造号称世界上最容易使用的安全private network产品。一些Go commiter和Ex-googler也被Fitzpatrick招入tailscale。Tailscale团队后续也成为了Go的重要贡献团队，比如<a href="https://github.com/go4org">go4org</a>下的很多实用包，像<a href="https://github.com/go4org/intern">intern</a>、<a href="https://tonybai.com/2023/04/16/understanding-unsafe-assume-no-moving-gc">unsafe-assume-no-moving-gc</a>、<a href="https://github.com/go4org/mem">mem</a>等。其中的intern还是<a href="https://github.com/golang/go/issues/62483">Go 1.23中加入的unique包</a>的灵感之源。</p>
<p>仍然活跃在Go开源社区的Fitzpatrick依旧继续为Go语言和其他开源项目做着贡献，他的热情和奉献精神使他成为Go社区中备受尊敬的领袖之一。</p>
<h2><a href="https://github.com/adg">Andrew Gerrand</a></h2>
<p>Andrew Gerrand是Go团队的早期成员之一，他为Go团队工作七年，早期也是Go项目的Top10贡献者。但他在Go团队的主要职责其实是围绕该语言构建社区并管理开源项目。Gerrand的工作帮助许多开发者快速上手Go语言。他编写的Go语言文章深入浅出，覆盖了从基础语法到高级特性的方方面面。此外，Gerrand还创建了Go Playground，一个在线编程环境，使开发者能够方便地编写和运行Go代码。</p>
<p>除了技术文档，Gerrand还积极参与社区活动。他组织和主持了多次Go语言会议（比如GopherCon）和用户组活动，推动了Go社区的建设和发展，是Rob Pike做Go社区推广的好搭档。。Gerrand还经常在Go语言的官方博客上发表文章，介绍Go的最新特性和最佳实践，官博早期的大部分文章都出自他手。由此看来，Gerrand在早期对Go语言的推广和社区建设做出过重要贡献。</p>
<p>从2016年开始，他跟随Rob Pike转战<a href="https://github.com/upspin/upspin">Upspin项目</a>，这个项目活跃了一年多，虽然现在依然在更新，但关注度目前已不是很高。Gerrand目前已经远离Go项目开发，并且很少撰文或参与Go社区活动。但他仍然在upspin、<a href="https://github.com/google/deps.dev">deps.dev</a>等google项目上使用Go进行着开发和维护工作。</p>
<p>如果要关注Gerrand的日常，可以<a href="https://twitter.com/enneff">在X上follow他的账号</a>。</p>
<h2><a href="https://swtch.com/~rsc/">Russ Cox</a></h2>
<p>Russ Cox是早期Go语言团队的重要成员之一，对Go语言的设计和实现做出了重大贡献。他拥有麻省理工学院的计算机科学博士学位，曾在贝尔实验室和Rob Pike一起在<a href="http://plan9.bell-labs.com/plan9">Plan9项目</a>上工作过。Cox在加入Google后，成为Go语言项目的核心开发者之一。</p>
<p>Russ Cox对Go的贡献是全方位的，无论在语言特性、工具链、社区推广等方面都有很大建树。这也使得他在Rob Pike退休后，迅速成为了Go语言的第二代领军人物。</p>
<p>近几年进入Go阵营的开发者对Russ Cox不可谓不熟悉，他主导了<a href="https://tonybai.com/2020/12/03/should-you-commit-the-vendor-folder-in-go">vendor</a>、type alias、<a href="https://go.dev/ref/mod">Go module</a>、<a href="https://tonybai.com/2022/03/25/intro-generics">泛型</a>等设计和实现，直接引领了Go的演进方向。</p>
<p>近几年，Russ Cox经常在GopherCon大会上代表Go团队发表主旨演讲，并在官博亲自撰文，向Go社区传达Go语言的演进思路与方向。经过多年历练，Russ Cox逐渐扛起了Go这杆大旗，接过了Rob Pike手中沉甸甸的Go接力棒。</p>
<h2><a href="https://github.com/dvyukov">Dmitry Vyukov</a></h2>
<p>Dmitry Vyukov是一位俄罗斯大神级程序员，英特尔并行编程黑带级程序员。加入Google后一直从事性能优化方面的工作，包括并发无锁算法、执行跟踪和竞争检测工具、fuzzing工具等。Vyukov虽然不是Go团队成员，但他对Go的贡献却是核心级的，主要包括：</p>
<ul>
<li><a href="https://tonybai.com/2017/06/23/an-intro-about-goroutine-scheduler/">Goroutine scheduler的设计和实现</a>，从G-M模型，到G-P-M模型，至今Goroutine scheduler还是在Vyukov实现的基础上修修补补的。他还提出了<a href="https://docs.google.com/document/d/1d3iI2QWURgDIsSR6G2275vMeQ_X7w-qxM2Vp7iGwwuM/pub">Go调度器的NUMA设计方案</a>，但目前尚未进入Go proposal流程</li>
<li><a href="https://tonybai.com/2021/06/28/understand-go-execution-tracer-by-example">Go execution tracer的设计和实现</a></li>
<li><a href="https://tonybai.com/2015/12/08/go-fuzz-intro/">设计和实现Go Fuzzing的早起雏形</a>，并<a href="https://tonybai.com/2021/12/01/first-class-fuzzing-in-go-1-18">推动Fuzzing进入Go项目</a>。</li>
</ul>
<p>除了技术贡献，Vyukov早期也会参与一些会议和社区活动，虽然不多，主要是推广Go execution tracer和<a href="https://tonybai.com/2015/12/08/go-fuzz-intro/">go-fuzz工具</a>。</p>
<p>目前，Vyukov依然在Google工作，也在继续为Go语言的发展做着力所能及的贡献。</p>
<h2><a href="https://spf13.com/about/">Steve Francia</a></h2>
<p>Steve Francia是早起Go语言社区的重要成员之一，对Go语言的推广和社区建设做出了重要贡献。Francia在加入Google之前，曾在MongoDB、Docker公司工作，拥有丰富的开发和管理经验。之后他加入Google，在Go语言项目中担任开发者关系经理，负责推动Go语言在企业中的应用。</p>
<p>Francia最为人称道的是他开发并开源的几个Go项目，包括<a href="https://tonybai.com/2015/09/23/intro-of-gohugo/">goHugo</a>、<a href="https://tonybai.com/2023/03/25/the-guide-of-developing-cli-program-in-go">Cobra</a>和<a href="https://tonybai.com/2022/09/20/use-viper-to-do-merge-of-yml-configuration-files/">viper</a>等。其中的hugo，一个基于Go语言的静态网站生成器，广受开发者的欢迎。</p>
<p>除了技术贡献，Francia还致力于社区建设。他组织和主持了多次Go语言会议和用户组活动，推动了Go社区的发展。Francia还在其<a href="https://spf13.com">个人博客</a>上撰写了大量关于Go语言的技术文档，为开发者提供了宝贵的学习资源。</p>
<p>目前，Francia已经离开了Google和Go团队，并在一家位于纽约的初创公司担任CTO。目前在Go社区，他已不再像以前那样活跃，但他的几个开源项目依然保持积极开发中，也有人协助他打理这些开源项目。</p>
<p>总之，Francia的工作对Go语言的普及和社区建设起到了重要的作用，帮助Go成为开发者们最喜爱的编程语言之一。</p>
<h2><a href="https://github.com/rakyll">Jaana Dogan</a></h2>
<p>Jaana Dogan是这个布道者列表中唯一的女性程序员。她曾是Go语言团队的一名工程师，对Go语言的性能优化、诊断和工具开发做出了重要贡献。但她在Go团队工作的时间并不长，很快就离开了Go团队，原因未知。目前她供职在github。</p>
<p>Dogan对社区的贡献主要体现在其<a href="https://rakyll.org/">关于Go的独特观点的博客文章</a>、<a href="https://go.dev/doc/diagnostics">诊断相关的技术文档</a>以及其开源的诸多项目，比如：<a href="https://github.com/rakyll/hey">hey</a>、<a href="https://github.com/google/gops">gops</a>、<a href="https://github.com/GoogleCloudPlatform/govanityurls">govanityurls</a>、<a href="https://github.com/rakyll/statik">statik</a>等。这些项目都不大，但却十分实用。</p>
<p>很多gopher中<a href="https://tonybai.com/2021/07/06/add-metrics-for-go-application-using-go-metrics">使用hey进行http压测</a>，gops则是高频使用的Go辅助诊断工具，govanityurls则是我的《<a href="https://tonybai.com/2021/09/03/the-approach-to-go-get-private-go-module-in-house">小厂内部私有Go module拉取方案</a>》的重要组件。statik也是<a href="https://tonybai.com/2021/02/25/some-changes-in-go-1-16">Go 1.16版本</a>引入<a href="https://tonybai.com/2020/12/12/a-forward-look-to-new-feature-of-go-1-16/">go:embed</a>之前在可执行文件中嵌入静态文件的一个可选工具。</p>
<p>Dogan在社区中以其深入的技术见解和乐于分享的态度，赢得了广泛的尊重和赞誉。不过，离开Google后，尤其是进入github后，Dogan在Go上面的投入似乎变少了很多，博客文章基本也不更新了，也没有新的开源项目产出，这对Go社区来说算是一个“损失”吧。</p>
<h2><a href="https://github.com/bketelsen">Brian Ketelsen</a>和<a href="https://github.com/erikstmartin">Erik St. Martin</a></h2>
<p>将Brian Ketelsen和Erik St. Martin放在一起说，是因为他们一起对Go语言以及Go社区的最大贡献就是共同创办了<a href="https://www.gophercon.com/">GopherCon</a>，这是全球最大也是最权威的Go语言开发者大会，每年都会吸引大量来自世界各地的Go开发者。GopherCon不仅是一个技术交流的平台，也是Go社区的重要聚会，促进了开发者之间的交流与合作。两人在组织和推动GopherCon的过程中，展示了他们对Go语言的热情和奉献精神。今年(2024年)也是GopherCon诞生的第10个年头，想必这又是一场Go语言和Go社区的盛会！</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-early-evangelists-of-go-7.jpg" alt="" /></p>
<p>除了会议组织和社区活动，Ketelsen和St. Martin还与William Kennedy联合撰写了关于Go语言的技术书籍<a href="https://book.douban.com/subject/25858023/">《Go in Action》</a>。这本书深入浅出地介绍了Go语言的基础知识和实际应用，为开发者提供了系统的学习资源。此外，他们还参与了多个开源项目，为Go语言的生态系统做出了重要贡献。</p>
<p>目前，Ketelsen和St. Martin都供职于微软公有云团队，仍然活跃在Go社区。</p>
<h2><a href="https://www.campoy.cat/">Francesc Campoy</a></h2>
<p>Francesc Campoy是Go语言社区的知名讲师和布道者，对Go语言的推广和普及做出了重要贡献。Campoy在加入Google之前，曾在西班牙的一家软件公司工作，拥有丰富的开发经验。他在Go语言项目中担任开发者关系经理，负责向开发者推广Go语言。Campoy也曾作为GopherChina的嘉宾在多年前来到中国布道！</p>
<p>Campoy的工作帮助许多开发者快速上手Go语言。他制作了一系列高质量的Go语言视频教程“<a href="https://youtube.com/c/justforfunc">Just for func</a>”，涵盖了从基础语法到高级特性的方方面面。这些视频教程深入浅出，受到了广泛的欢迎。此外，Campoy还创建了Go语言的官方YouTube频道，定期发布技术讲座和演示，进一步推动了Go语言的普及。</p>
<p>2016年，Campoy从Google离职，加入<a href="https://dgraph.io/">Dgraph Labs</a>，负责原生GraphQL数据库<a href="https://github.com/dgraph-io/dgraph">dgraph</a>以及<a href="https://github.com/dgraph-io/badger">键值数据库badger</a>的开发。后来Dgraph labs内讧，Campoy转投到apple名下。</p>
<p>进入Apple后，Campoy就渐渐从Go社区淡出了。但他仍然会进行一些Go项目的开发，Github的activity中有他的一些活动记录，但更多地是对私有仓库的贡献。</p>
<h2><a href="https://dave.cheney.net/">Dave Cheney</a></h2>
<p>如果说Go团队之外，谁是大家最喜欢的Go布道师和意见领袖，<strong>矮胖子Dave Cheney</strong>肯定可以拿到数一数二的选票。</p>
<p>相信早期学过Go语言的Gopher们，没有没读过Dave Cheney的个人博客的。他的博客从2010开始写的内容就几乎都与Go相关，并且思维缜密，写作风格深入浅出，颇受Gopher欢迎。</p>
<p>很多人还参与过他在世界各地举办的Go用户活动。Dave Cheney也是来到中国GopherChina大会最多的Go布道师，为中国Gopher带来了精彩的演讲以及<a href="https://dave.cheney.net/practical-go/presentations/qcon-china.html">极具干货的大会前Workshop</a>。</p>
<p>除了技术资料外，Dave Cheney早期在Go项目的issue上、在<a href="https://groups.google.com/g/golang-nuts">go-nuts邮件列表</a>以及stackoverflow上也是非常活跃，非常乐于帮助那些想给Go项目做出贡献的gopher融入。同时他在github.com/pkg下开源的诸多项目也非常实用（比如https://github.com/pkg/errors），深受大家欢迎。</p>
<p>更多关于Dave Cheney对Go语言的贡献，可以阅读其<a href="https://dave.cheney.net/about">个人博客的about页面</a>。</p>
<p>不过不知何故，从2021年初开始，Dave Cheney的博客开始停更，他在社区的声音也逐渐消失。直到今年年初，Dave Cheney才又更新了一篇名为<a href="https://dave.cheney.net/2024/02/22/microblog-testmain-can-cause-one-to-question-reality">“Microblog: TestMain can cause one to question reality”</a>的文章。</p>
<p>不过从Dave Cheney的github Contribution activity来看，Dave仍然在大量的编写代码，只是这些代码是commit到private仓库的。</p>
<p>希望Dave Cheney能早日回归Go社区，并恢复当初的那份热忱。</p>
<h2><a href="https://twitter.com/goinggodotnet">Bill Kennedy</a></h2>
<p>Bill Kennedy是Go语言社区的知名讲师和布道者，对Go语言的推广和普及做出了重要贡献，并且这种贡献一直持续至今。</p>
<p>Kennedy是<a href="https://www.ardanlabs.com/">ardan labs</a>的CTO，也是该公司的主要讲师，他最拿手的Ultimate Go培训已经开办了十多年了，每年都会在全球进行很多场培训，此外，GopherCon大会前的Workshop总是少不了Bill Kennedy的training。</p>
<p>除了Training，Ardan Labs早期的博客文章也堪称精品，不少Gopher因这些文章而受益！Kennedy的工作主要是帮助许多开发者快速上手Go语言。他还撰写了多本关于Go语言的技术书籍，如《Go in Action》和《Ultimate Go》。这些书籍深入浅出，涵盖了从基础语法到高级特性的方方面面，为开发者提供了系统的学习资源。</p>
<p>除了技术培训，Kennedy还积极参与Go语言演进和Go社区活动之中，这其中一个最典型的事件就是2019年他代表广大Gopher用户发<a href="https://www.ardanlabs.com/blog/2019/07/an-open-letter-to-the-go-team-about-try.html">给Go团队的公开信</a>，极力组织不成熟的try关键字提案进入Go语言。</p>
<p>目前，Kennedy依然活跃在Go社区，继续推动Go语言的发展和普及。</p>
<h2><a href="https://github.com/matryer">Mat Ryer</a></h2>
<p>Mat Ryer是Go语言社区的一位资深开发者和布道者，他是一名英国程序员。他之前在Go社区非常活跃，积极参与技术会议和社区活动，分享Go语言在实际项目中的应用经验和最佳实践，其中最持久的莫过于主持<a href="https://changelog.com/gotime">Go Time播客</a>了！”Go Time”是一个专注于Go编程语言的播客节目。该播客由Changelog Media出品，主要内容涵盖了Go语言的新特性、最佳实践、社区新闻、工具和库的推荐，以及与Go生态系统相关的各种话题。节目通常会邀请Go社区的知名开发者、贡献者和专家作为嘉宾，分享他们的经验和见解。截至写本文时，该播客已经发布了315期，每期都有音频和<a href="https://github.com/thechangelog/transcripts/blob/master/gotime/">文字稿</a>。</p>
<p>除了上述活动，Mat Ryer还是<a href="https://book.douban.com/subject/26907929/">《Go Programming Blueprints》</a>一书的作者。</p>
<p>如今Mat Ryer依然活跃在Go社区，他供职于Grafana，依然从事着Go语言开源项目的开发，同时主持Go Time播客以及组织和参与各种Go用户会议。</p>
<h2>参考资料</h2>
<ul>
<li><a href="https://golang.design/history/">Go history</a> &#8211; https://golang.design/history/</li>
</ul>
<hr />
<p><a href="https://public.zsxq.com/groups/51284458844544">Gopher部落知识星球</a>在2024年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。同时，我们也会加强代码质量和最佳实践的分享，包括如何编写简洁、可读、可测试的Go代码。此外，我们还会加强星友之间的交流和互动。欢迎大家踊跃提问，分享心得，讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落，享受coding的快乐! 欢迎大家踊跃加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-tribe-zsxq-small-card.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/go-programming-from-beginner-to-master-qr.png" alt="img{512x368}" /></p>
<p><img src="http://image.tonybai.com/img/tonybai/go-first-course-banner.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/imooc-go-column-pgo-with-qr.jpg" alt="img{512x368}" /></p>
<p>著名云主机服务厂商DigitalOcean发布最新的主机计划，入门级Droplet配置升级为：1 core CPU、1G内存、25G高速SSD，价格5$/月。有使用DigitalOcean需求的朋友，可以打开这个<a href="https://m.do.co/c/bff6eed92687">链接地址</a>：https://m.do.co/c/bff6eed92687 开启你的DO主机之路。</p>
<p>Gopher Daily(Gopher每日新闻) &#8211; https://gopherdaily.tonybai.com</p>
<p>我的联系方式：</p>
<ul>
<li>微博(暂不可用)：https://weibo.com/bigwhite20xx</li>
<li>微博2：https://weibo.com/u/6484441286</li>
<li>博客：tonybai.com</li>
<li>github: https://github.com/bigwhite</li>
<li>Gopher Daily归档 &#8211; https://github.com/bigwhite/gopherdaily</li>
</ul>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。</p>
<p style='text-align:left'>&copy; 2024, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2024/05/17/the-early-evangelists-of-go/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Go语言之父的反思：我们做对了什么，做错了什么</title>
		<link>https://tonybai.com/2024/01/07/what-we-got-right-what-we-got-wrong/</link>
		<comments>https://tonybai.com/2024/01/07/what-we-got-right-what-we-got-wrong/#comments</comments>
		<pubDate>Sun, 07 Jan 2024 11:33:46 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[Channel]]></category>
		<category><![CDATA[Compiler]]></category>
		<category><![CDATA[CSP]]></category>
		<category><![CDATA[generics]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[go.dev]]></category>
		<category><![CDATA[gofmt]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Gopher]]></category>
		<category><![CDATA[GopherCon]]></category>
		<category><![CDATA[GopherConAu]]></category>
		<category><![CDATA[goroutine]]></category>
		<category><![CDATA[IDE]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[LLVM]]></category>
		<category><![CDATA[Opensource]]></category>
		<category><![CDATA[plan9]]></category>
		<category><![CDATA[Pthread]]></category>
		<category><![CDATA[RobPike]]></category>
		<category><![CDATA[RussCox]]></category>
		<category><![CDATA[select]]></category>
		<category><![CDATA[Specification]]></category>
		<category><![CDATA[SSA]]></category>
		<category><![CDATA[svn]]></category>
		<category><![CDATA[typeparameter]]></category>
		<category><![CDATA[vet]]></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=4103</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2024/01/07/what-we-got-right-what-we-got-wrong 在《2023年Go语言盘点：稳中求新，稳中求变》和《Go测试的20个实用建议》两篇文章中，我都提到过已经退居二线的Go语言之父Rob Pike在Go开源14周年的那天亲自在GopherCon Australia 2023上发表了“What We Got Right, What We Got Wrong”的主题演讲来回顾Go诞生以来的得与失。近期Rob Pike终于将这次演进的文字稿发布了出来！GopherCon Australia也在油管上发布了这个演进的视频。Rob Pike的观点对所有Gopher都是极具参考价值的，因此在这篇博文中，我将Rob Pike的这次演讲稿翻译成中文，供大家参考(结合文字稿和视频)，我们一起来领略和学习大师的观点。 这是2023年11月10日我在悉尼GopherConAU 2023会议上的闭幕演讲（视频），那一天也是Go开源14周年的日子。本文中穿插着演示文稿中使用的幻灯片。 介绍 大家好！ 首先，我要感谢Katie和Chewy让我有幸为此次GopherConAU大会做闭幕演讲。 2009年11月10日 今天是2023年11月10日，Go作为开源项目推出14周年的纪念日。 2009年11月10日那天，加州时间下午3点（如果没记错的话），Ken Thompson、Robert Griesemer、Russ Cox、Ian Taylor、Adam Langley、Jini Kim和我满怀期待地看着网站上线。之后，全世界都知道我们在做什么了。 14年后的今天，有很多事情值得回顾。我想借此机会谈谈自那一天以来学到的一些重要经验。即使是最成功的项目，在反思之后，也会发现一些事情本可以做得更好。当然，也有一些事情事后看来似乎是成功的关键所在。 首先，我必须明确的是，这里的观点只代表我个人，不代表Go团队和Google。无论是过去还是现在，Go都是由一支专注的团队和庞大的社区付出巨大努力的结果。所以，如果你同意我的任何说法，请感谢他们。如果你不同意，请责怪我，但请保留你的意见。 鉴于本次演讲的题目，许多人可能期待我会分析语言中的优点和缺点。当然，我会做一些分析，但还会有更多内容，原因有几个。 首先，编程语言的好坏很大程度上取决于观点而不是事实，尽管许多人对Go或任何其他语言的最微不足道的功能都存在争论。 另外，关于换行符的位置、nil的工作方式、导出的大小写表示法、垃圾回收、错误处理等话题已经有了大量的讨论。这些话题肯定有值得讨论的地方，但几乎没什么是还没有被讨论过的。 但我要讨论的不仅仅是语言本身的真正原因是，语言并不是整个项目的全部。我们最初的目标不是创造一种新的编程语言，而是创造一种更好的编写软件的方式。我们对所使用的语言有意见——无论使用什么语言，每个人都是如此——但是我们遇到的基本问题与这些语言的特性没有太大关系，而是与在谷歌使用这些语言构建软件的过程有关。 T恤上的第一只Gopher 新语言的创建提供了探索其他想法的新路径，但这只是一个推动因素，而不是真正的重点。如果当时我正在工作的二进制文件不需要45分钟来构建 ，Go语言就不会出现。但那45分钟不是因为编译器慢(因为它不慢)，也不是因为它所用的语言不好(因为它也不差)。缓慢是由其他因素造成的。 我们想解决的就是这些因素：构建现代服务器软件的复杂性：控制依赖性、与人员不断变化的大型团队一起编程、可维护性、高效测试、多核CPU和网络的有效利用等等。 简而言之，Go不仅仅是一种编程语言。当然，它是一种编程语言，这是它的定义。但它的目的是帮助提供一种更好的方式来开发高质量的软件，至少与14多年前的我们的环境相比。 时至今日，这仍然是它的宗旨。Go是一个使构建生产软件更容易、更高效的项目。 几周前，当我开始准备这次演讲时，我只有一个题目，除此之外别无其他。为了激发我的思路，我在Mastodon上向人们征求意见。不少人给予了回复。我注意到了一种趋势：人们认为我们做错的事情都在语言本身，而我们做对的事情都在语言周边，比如gofmt、部署和测试等。事实上，我觉得这令人鼓舞。我们试图做的事情似乎已经产生了效果。 但值得承认的是，我们在早期并没有明确真正的目标。我们可能觉得这些目标是不言自明的。为了弥补这一缺陷，我在2013年的SPLASH会议上发表了一场题为《谷歌的Go语言：面向软件工程的语言设计》的演讲。 Go at Google 那场演讲和相关的博客文章可能是对Go语言为何而生的最好诠释。 今天的演讲是SPLASH演讲的后续，回顾了我们在构建语言之后所学到的经验教训，并且可以更广泛地应用于更大的图景。 那么&#8230;&#8230;来谈谈一些教训。 首先，当然，我们有： The Gopher [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2024/01/07/what-we-got-right-what-we-got-wrong">本文永久链接</a> &#8211; https://tonybai.com/2024/01/07/what-we-got-right-what-we-got-wrong</p>
<p>在《<a href="https://tonybai.com/2023/12/31/the-2023-review-of-go-programming-language/">2023年Go语言盘点：稳中求新，稳中求变</a>》和《<a href="https://tonybai.com/2024/01/01/go-testing-by-example/">Go测试的20个实用建议</a>》两篇文章中，我都提到过已经退居二线的<a href="https://tonybai.com/2023/12/11/simplicity/">Go语言之父Rob Pike</a>在<a href="https://tonybai.com/2023/11/11/go-opensource-14-years/">Go开源14周年</a>的那天亲自在GopherCon Australia 2023上发表了“What We Got Right, What We Got Wrong”的主题演讲来回顾Go诞生以来的得与失。近期<a href="https://commandcenter.blogspot.com/2024/01/what-we-got-right-what-we-got-wrong.html">Rob Pike终于将这次演进的文字稿发布了出来</a>！<a href="https://www.youtube.com/watch?v=yE5Tpp2BSGw">GopherCon Australia也在油管上发布了这个演进的视频</a>。Rob Pike的观点对所有Gopher都是极具参考价值的，因此在这篇博文中，我将Rob Pike的这次演讲稿翻译成中文，供大家参考(结合文字稿和视频)，我们一起来领略和学习大师的观点。</p>
<hr />
<p>这是2023年11月10日我<a href="https://www.youtube.com/watch?v=yE5Tpp2BSGw">在悉尼GopherConAU 2023会议上的闭幕演讲（视频）</a>，那一天也是<a href="https://tonybai.com/2023/11/11/go-opensource-14-years">Go开源14周年</a>的日子。本文中穿插着演示文稿中使用的幻灯片。</p>
<h2>介绍</h2>
<p>大家好！</p>
<p>首先，我要感谢Katie和Chewy让我有幸为此次GopherConAU大会做闭幕演讲。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-2.png" alt="" /><br />
<center>2009年11月10日</center></p>
<p>今天是2023年11月10日，Go作为开源项目推出14周年的纪念日。</p>
<p>2009年11月10日那天，加州时间下午3点（如果没记错的话），Ken Thompson、Robert Griesemer、Russ Cox、Ian Taylor、Adam Langley、Jini Kim和我满怀期待地看着网站上线。之后，全世界都知道我们在做什么了。</p>
<p>14年后的今天，有很多事情值得回顾。我想借此机会谈谈自那一天以来学到的一些重要经验。即使是最成功的项目，在反思之后，也会发现一些事情本可以做得更好。当然，也有一些事情事后看来似乎是成功的关键所在。</p>
<p>首先，我必须明确的是，这里的观点只代表我个人，不代表Go团队和Google。无论是过去还是现在，Go都是由一支专注的团队和庞大的社区付出巨大努力的结果。所以，如果你同意我的任何说法，请感谢他们。如果你不同意，请责怪我，但请保留你的意见。</p>
<p>鉴于本次演讲的题目，许多人可能期待我会分析语言中的优点和缺点。当然，我会做一些分析，但还会有更多内容，原因有几个。</p>
<p>首先，编程语言的好坏很大程度上取决于观点而不是事实，尽管许多人对Go或任何其他语言的最微不足道的功能都存在争论。</p>
<p>另外，关于换行符的位置、nil的工作方式、导出的大小写表示法、垃圾回收、错误处理等话题已经有了大量的讨论。这些话题肯定有值得讨论的地方，但几乎没什么是还没有被讨论过的。</p>
<p>但我要讨论的不仅仅是语言本身的真正原因是，语言并不是整个项目的全部。我们最初的目标不是创造一种新的编程语言，而是<a href="https://tonybai.com/2022/05/04/the-paper-of-go-programming-language-and-environment">创造一种更好的编写软件的方式</a>。我们对所使用的语言有意见——无论使用什么语言，每个人都是如此——但是我们遇到的基本问题与这些语言的特性没有太大关系，而是与在谷歌使用这些语言构建软件的过程有关。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-3.png" alt="" /><br />
<center>T恤上的第一只Gopher</center></p>
<p>新语言的创建提供了探索其他想法的新路径，但这只是一个推动因素，而不是真正的重点。如果当时我正在工作的二进制文件不需要45分钟来构建<br />
，Go语言就不会出现。但那45分钟不是因为编译器慢(因为它不慢)，也不是因为它所用的语言不好(因为它也不差)。缓慢是由其他因素造成的。</p>
<p>我们想解决的就是这些因素：构建现代服务器软件的复杂性：控制依赖性、与人员不断变化的大型团队一起编程、可维护性、高效测试、多核CPU和网络的有效利用等等。</p>
<p>简而言之，Go不仅仅是一种编程语言。当然，它是一种编程语言，这是它的定义。但它的目的是帮助提供一种更好的方式来开发高质量的软件，至少与14多年前的我们的环境相比。</p>
<p>时至今日，这仍然是它的宗旨。Go是一个使构建生产软件更容易、更高效的项目。</p>
<p>几周前，当我开始准备这次演讲时，我只有一个题目，除此之外别无其他。为了激发我的思路，我在Mastodon上向人们征求意见。不少人给予了回复。我注意到了一种趋势：人们认为我们做错的事情都在语言本身，而我们做对的事情都在语言周边，比如gofmt、部署和测试等。事实上，我觉得这令人鼓舞。我们试图做的事情似乎已经产生了效果。</p>
<p>但值得承认的是，我们在早期并没有明确真正的目标。我们可能觉得这些目标是不言自明的。为了弥补这一缺陷，我在2013年的SPLASH会议上发表了一场题为《<a href="https://go.dev/talks/2012/splash.article">谷歌的Go语言：面向软件工程的语言设计</a>》的演讲。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-4.png" alt="" /><br />
<center>Go at Google</center></p>
<p>那场演讲和相关的博客文章可能是对Go语言为何而生的最好诠释。</p>
<p>今天的演讲是SPLASH演讲的后续，回顾了我们在构建语言之后所学到的经验教训，并且可以更广泛地应用于更大的图景。</p>
<p>那么&#8230;&#8230;来谈谈一些教训。</p>
<p>首先，当然，我们有：</p>
<h2>The Gopher</h2>
<p>以Go Gopher吉祥物开始可能看起来是一个奇怪的起点，但Go gopher是Go成功的最早因素之一。在发布Go之前，我们就知道我们想要一个吉祥物来装饰周边商品——每个项目都需要周边商品——Renee French主动提出为我们制作一个这样的吉祥物。在这一点上，我们做得非常正确。</p>
<p>下面最早的Gopher毛绒玩具的图片：</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-5.jpeg" alt="" /><br />
<center>The Gopher</center></p>
<p>这是Gopher的照片，它的第一个原型不太成功。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-6.jpeg" alt="" /><br />
<center>Gopher和它进化程度较低的祖先</center></p>
<p>Gopher是一个吉祥物，它也是荣誉徽章，甚至是世界各地Go程序员的身份标志。此时此刻，你正在参加一个名为GopherCon的会议，这是众多GopherCon会议中的一个。拥有一个从第一天就准备好分享信息的容易识别、有趣的生物，对Go的成长至关重要。它天真又聪明——它可以构建任何东西!</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-7.jpeg" alt="" /><br />
<center>Gopher建造机器人（Renee French 绘图）</center></p>
<p>它为社区参与该项目奠定了基调，这是卓越的技术与真正的乐趣相结合的基调。最重要的是，Gopher是社区的一面旗帜，一面团结起来的旗帜，尤其是在早期，当Go还是编程界的新贵时。</p>
<p>这是几年前Gopher参加巴黎会议的照片，看看他们多兴奋！</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-8.png" alt="" /><br />
<center>巴黎的Gopher观众（Brad Fitzpatrick摄）</center></p>
<p>尽管如此，在知识共享署名许可(Creative Commons Attribution license)下发布Gopher的设计也许不是最好的选择。一方面，它鼓励人们以有趣的方式重新组合他，这反过来又有助于培养社区精神。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-9.png" alt="" /><br />
<center>Gopher model sheet</center></p>
<p>Renee创建了一个“模型表”来帮助艺术家在保持其精神原貌的同时进行艺术创作。</p>
<p>一些艺术家利用这些特征制作了自己版本的Gopher并获得了乐趣；Renee和我最喜欢的版本是日本设计师@tottie的和游戏程序员@tenntennen的：</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-10.jpeg" alt="" /><br />
<center>@tottie的Gopher</center></p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-11.png" alt="" /><br />
<center>@tenntennen 的gopher</center></p>
<p>但许可证的“归属”部分常常会导致令人沮丧的争论，或者导致Renee的创作不属于她，也不符合原作的精神。而且，说实话，这种归属往往只是不情愿地得到尊重，或者根本没有得到尊重。例如，我怀疑@tenntennen是否因他的Gopher插图被使用而获得补偿或是得到承认。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-12.png" alt="" /><br />
<center>gophervans.com: Boo!</center></p>
<p>因此，如果让我们重来一次，我们会认真思考确保吉祥物忠于其理想的最佳方法。维护吉祥物是一件很难的事，而且解决方案仍然难以捉摸。</p>
<p>但更多的是技术性的事情。</p>
<h2>做的对的事情</h2>
<p>这里有一份我认为我们在客观上做对了的事情的清单，特别是在回顾的时候。并不是每一个编程语言项目都做了这些事情，但清单中的每一件对Go的最终成功都至关重要。我会试着言简意赅，因为这些话题都已为人所熟知。</p>
<h3>1. 语言规范(Specification)</h3>
<p>我们从正式的语言规范开始。这不仅可以在编写编译器时锁定行为，还可以使多个编译器实现共存并就该行为达成一致。编译器本身并不是一个规范。你测试编译器的依据是什么？</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-13.png" alt="" /><br />
<center>Web上的Go语言规范</center></p>
<p>哦，顺便说一句，该规范的初稿是在这里编写的，位于悉尼达令港一栋建筑的18层。我们正在Go的家乡庆祝Go的生日。</p>
<h3>2. 多种实现</h3>
<p>Go有多个编译器实现，它们都实现相同的语言规范。有了规范就可以更容易地实现这一点。</p>
<p>有一天，伊恩·泰勒（Ian Taylor）发邮件通知我们，在阅读了我们的语言规范草案后，他自己编写了一个编译器，这让我们感到惊讶！</p>
<pre><code>Subject: A gcc frontend for Go
From: Ian Lance Taylor
Date: Sat, Jun 7, 2008 at 7:06 PM
To: Robert Griesemer, Rob Pike, Ken Thompson

One of my office-mates pointed me at http://.../go_lang.html .  It
seems like an interesting language, and I threw together a gcc
frontend for it.  It's missing a lot of features, of course, but it
does compile the prime sieve code on the web page.
</code></pre>
<p>这的确令人兴奋，但更多的编译器实现也随之而来了，所有这些都因正式规范的存在而成为可能。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-14.jpeg" alt="" /><br />
<center>很多编译器</center></p>
<p>拥有多个编译器帮助我们改进了语言并完善了规范，并为那些不太喜欢我们类似Plan-9的业务方式的其他人提供了替代环境。稍后会详细介绍。如今有很多兼容的实现，这很棒！</p>
<h3>3. 可移植性</h3>
<p>我们使Go应用的交叉编译变得轻而易举，程序员可以在他们喜欢的任何平台上工作，并交付到任何需要的平台。使用Go可能比使用任何其他语言更容易达成这一点。很容易将编译器视为运行它的机器的本地编译器，但没有理由这么认为。打破这个假设具有重要意义，这对许多开发者来说都是新鲜事。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-15.png" alt="" /><br />
<center>可移植性</center></p>
<h3>4. 兼容性</h3>
<p>我们努力使语言达到1.0版本的标准，然后通过兼容性保证将其固定下来，这对Go的采用产生了非常明显的影响！我不理解为什么大多数其他项目一直在抵制这样做。是的，保持强大兼容性的确需要付出成本，但它可以阻止功能特性停滞，而在这个几乎没有其他东西保持稳定的世界里，不必担心新版本的Go会破坏你的项目，这足以令人感到欣喜！</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-16.png" alt="" /><br />
<center>Go兼容性承诺</center></p>
<h3>5. 标准库</h3>
<p>尽管它的增长在某种程度上是偶然的，因为在一开始没有其他地方可以安装Go代码，但拥有一个坚实、制作精良的标准库，其中包含编写21世纪服务器代码所需的大部分内容，这是一个重大资产。在我们积累了足够的经验来理解还应该提供什么之前，它使整个社区都使用相同的工具包。这非常有效，并有助于防止出现不同版本的库，从而帮助统一社区。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-17.jpeg" alt="" /><br />
<center>标准库</center></p>
<h3>6. 工具</h3>
<p>我们确保该语言易于解析，从而支持工具构建。起初我们认为Go需要一个IDE，但易于构建工具意味着，随着时间的推移，IDE将会出现在Go上。他们和gopls一起做到了，而且他们非常棒。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-18.jpeg" alt="" /><br />
<center>工具</center></p>
<p>我们还为编译器提供了一套辅助工具，例如自动化测试、覆盖率和代码审查(code vetting)。当然还有go命令，它集成了整个构建过程，也是许多项目构建和维护其Go代码所需的一切。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-19.jpeg" alt="" /><br />
<center>快速构建</center></p>
<p>此外，Go获得了快速构建的声誉，这也没有什么坏处。</p>
<h3>7. Gofmt</h3>
<p>我将gofmt作为一个单独的项目从工具中拿出来，因为它是一个不仅在Go上而且在整个编程社区上留下了印记的工具。在Robert编写gofmt之前（顺便说一句，他从一开始就坚持这样做），自动格式化程序的质量不高，因此大多未被使用。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-20.png" alt="" /><br />
<center>gofmt谚语</center></p>
<p>gofmt的成功表明了代码自动格式化可以做得很好，今天几乎每种值得使用的编程语言都有一个标准格式化程序。我们不再为空格和换行符争论，这节省了大量时间了，这也让那些花在定义标准格式和编写这段相当困难的代码实现格式自动化上的时间显得超值。</p>
<p>此外，gofmt还使无数其他工具成为可能，例如简化器、分析器甚至是代码覆盖率工具。因为gofmt的内容成为了任何人都可以使用的库，所以你可以解析程序、编辑AST，然后打印完美的字节输出，供人类和机器使用。</p>
<p>谢谢，罗伯特。</p>
<p>不过，恭喜你就够了。接下来，我们来谈谈一些更有争议的话题。</p>
<h2>并发性</h2>
<p>并发有争议吗？嗯，在我2002年加入谷歌的那年肯定有。John Ousterhout曾说过：线程很糟糕。许多人都同意他的观点，因为线程似乎非常难以使用。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-21.png" alt="" /><br />
<center>John Ousterhout不喜欢线程</center></p>
<p>谷歌的软件几乎总是避免使用它们，可以说是彻底禁止使用，而制定这一禁令的工程师引用了Ousterhout的言论。这让我很困扰。自20世纪70年代以来，我一直在做类似的并发事情，有时候甚至没有意识到，在我看来这很强大。但经过反思，很明显Ousterhout犯了两个错误。首先，他的结论超出了他有兴趣使用线程的领域，其次，他主要是在抱怨使用笨拙的低级包如pthread之类的线程，而不是抱怨这一基本思想。</p>
<p>像这样混淆解决方案和问题是世界各地工程师常犯的错误。有时，提出的解决方案比它解决的问题更难，并且很难看到有更简单的路径。但我离题了。</p>
<p>根据经验，我知道有更好的方法来使用线程，或者无论我们选择怎么称呼它们，我甚至在Go语言出现之前就曾就此发表过演讲。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-22.png" alt="" /><br />
<center>Newsqueak中的并发</center></p>
<p>但我并不孤单，其他许多语言、论文甚至书籍都表明，并发编程可以做得很好，不仅我知道这一点。它只是还没有在主流中流行起来，Go的诞生部分地就是为了解决这个问题。在那次臭名昭著的45分钟构建中，我试图向一个非线程二进制文件添加一个线程，这非常困难，因为我们使用了错误的工具。</p>
<p>回顾过去，我认为可以公平地说，Go在让编程界相信并发是一种强大工具方面发挥了重要作用，特别是在多核网络世界中，它可以比pthread做得更好。如今，大多数主流语言都对并发提供了很好地支持。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-23.png" alt="" /><br />
<center>Google 3.0</center></p>
<p>另外，Go的并发版本在导致它出现的语言线中有些新颖，因为它使goroutine变得平淡无奇。没有协程，没有任务，没有线程，没有名称，只有goroutine。我们发明了“goroutine”这个词，因为没有适合的现有术语。时至今日，我仍然希望Unix的拼写命令可以学会它。</p>
<p>顺便说一句，因为我经常被问到，让我花一分钟时间谈谈async/await。看到async/await模型及其相关风格成为许多语言选择支持并发的方式，我有点难过，但它肯定是对pthreads的巨大改进。</p>
<p>与goroutine、channel和select相比，async/await对语言实现者来说更容易也更小，可以更容易地内建或后移植到现有平台中。但它将一些复杂性推回给了程序员，通常会导致Bob Nystrom所著名的“<a href="https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/">彩色函数</a>”。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-24.png" alt="" /><br />
<center>你的函数是什么颜色的</center></p>
<p>我认为Go表明了CSP这种不同但更古老的模型可以完美地嵌入到过程化语言中，没有这种复杂性。我甚至看到它几次作为库实现。但它的实现，如果做得好，需要显著的运行时复杂性，我可以理解为什么一些人更倾向于不在他们的系统中内置它。不管你提供什么并发模型，重要的是只提供一次，因为一个环境提供多个并发实现可能会很麻烦。Go当然通过把它放在语言中而不是库中解决了这个问题。</p>
<p>关于这些问题可能要讲整场演讲，但目前就这些吧。</p>
<p>并发的另一个价值在于，它使Go看起来像是全新的东西。如我所说，一些其他语言在之前已经支持了它，但它们从未进入主流，而Go对并发的支持是吸引初学者采用的一个主要因素，它吸引了以前没有使用过并发但对其可能性感兴趣的程序员。</p>
<p>这就是我们犯下两个大错误的地方。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-25.png" alt="" /><br />
<center>耳语的Gopher(Cooperating Sequential Processes)</center></p>
<p>首先，并发很有趣，我们很高兴拥有它，但我们设想的使用案例大多是服务器相关的，意在在net/http等关键库中完成，而不是在每个程序的所有地方完成。当许多程序员使用它时，他们努力研究它如何真正帮助他们。我们应该一开始就解释清楚，语言中的并发支持真正带到桌面的是更简单的服务器软件。这个问题空间对许多人很重要，但并非所有尝试Go的人都是如此，这点指导不足是我们的责任。</p>
<p>相关的第二点是，我们用了太长时间来澄清并行和并发之间的区别——支持在多核机器上并行执行多个计算，以及一种组织代码的方式，以便很好地执行并行计算。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-26.png" alt="" /><br />
<center>并发不是并行</center></p>
<p>无数程序员试图通过使用goroutine来并行化他们的代码以使其更快，但经常对结果中的速度降低感到困惑。仅当基础问题本质上是并行的时候，例如服务HTTP请求，并发代码才会通过并行化而变快。我们在解释这一点上做得很糟糕，结果让许多程序员感到困惑，可能还赶走了一些人。</p>
<p>为了解决这个问题，我在2012年Waza上给Heroku的开发者大会做了一个题为“<a href="https://www.youtube.com/watch?v=oV9rvDllKEg">并发不是并行</a>”的演讲。这是一次很有趣的演讲，但它应该更早发生。</p>
<p>对此表示歉意。但好处仍然存在：Go帮助普及了并发性作为构建服务器软件的一种方式。</p>
<h2>接口</h2>
<p>很明显，接口与并发都是Go中与众不同的思想。它们是Go对面向对象设计的答案，采用最初关注行为的风格，尽管新来者一直在努力使结构体承担这一角色。</p>
<p>使接口动态化，无需提前宣布哪些类型实现了它们，这困扰了一些早期评论者，并且仍然恼火一小部分人，但它对Go培育的编程风格很重要。大部分标准库都是建立在它们的基础之上的，而更广泛的主题如测试和管理依赖也高度依赖于它们慷慨的“欢迎所有人”的天性。</p>
<p>我觉得接口是Go中设计最好的部分之一。</p>
<p>除了一些早期关于接口定义中是否应该包括数据的讨论之外，它们在讨论的第一天就已经成形。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-27.png" alt="" /><br />
<center>GIF 解码器：Go接口的练习（Rob Pike和Nigel Tao 2011）</center></p>
<p>在这个问题上还有一个故事要讲。</p>
<p>在Robert和我的办公室里那著名的第一天，我们讨论了关于多态性应该怎么处理的问题。Ken和我从C语言中知道qsort可以作为一个困难的测试用例，所以我们三个人开始讨论用我们这种初具雏形的语言如何实现一个类型安全的排序例程(routine)。</p>
<p>Robert和我几乎同时产生了同样的想法：在类型上使用方法来提供排序所需的操作。这个概念很快发展成了一个想法，即值类型拥有作为方法定义的行为，一组方法可以提供函数可以操作的接口。Go的接口几乎立即就出现了。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-28.png" alt="" /><br />
<center>sort.Interface</center></p>
<p>有一点没人经常提到：Go的sort函数是作为一个在接口上操作的函数实现的。这与大多数人熟悉的面向对象编程风格不同，但这是一个非常强大的想法。</p>
<p>这个想法对我们来说非常激动人心，它可能成为一个基础的编程构造，这令我们陶醉。当Russ Cox加入时，他很快指出了I/O如何完美地融入这个想法，标准库的发展非常迅速，在很大程度上依赖于三个著名的接口：空接口(interface{})、Writer和Reader，每个接口平均包含两个第三个方法。那些微小的方法对Go来说是惯用法，无处不在。</p>
<p>接口的工作方式不仅成为Go的一个显著特性，它们也成为我们思考库、泛型和组合的方式。这是让人兴奋的事情。</p>
<p>但我们在这个问题上停止讨论可能是一个错误。</p>
<p>你看，我们之所以走上这条路，至少在一定程度上是因为我们看到泛型编程太容易鼓励一种倾向于在算法之前首先关注类型的思考方式。过早抽象而不是有机设计。容器而不是函数。</p>
<p>我们在语言中正确定义了通用容器——map，切片，数组，channel——而不给程序员访问它们所包含的泛型。这可以说是一个错误。我们相信，我认为仍然正确的是，大多数简单的编程任务可以很好地由这些类型来处理。但有一些不能，语言提供的和用户可以控制的之间的障碍肯定困扰了一些人。</p>
<p>简而言之，尽管我不会改变接口的任何工作方式，但它们以需要十多年时间才能纠正的方式影响了我们的思维。Ian Taylor从一开始就推动我们面对这个问题，但在接口作为Go编程基石的情况下，这是相当困难的。</p>
<p>评论者经常抱怨我们应该使用泛型，因为它们“很简单”，在某些语言中可能确实如此，但接口的存在意味着任何新的多态形式都必须考虑到它们。找到一种可以与语言的其余部分很好地协同工作的前进方法需要多次尝试，几次中止的实现，以及许多小时、天数和周数的讨论。最终，在Phil Wadler的带领下，我们召集了一些类型理论家来提供帮助。即使在语言中有了可靠的泛型模型，作为方法集存在的接口也仍然存在一些遗留问题。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-29.png" alt="" /><br />
<center>泛型版sort</center></p>
<p>如你所知，最终的答案是设计一个可以吸收更多多态形式的接口泛化，从“方法集合”过渡到“类型集合”。这是一个微妙但深刻的举措，大多数社区似乎都可以接受，尽管我怀疑抱怨声永远不会停止。</p>
<p>有时候要花很多年的时间来弄清楚一些事情，或者甚至弄清楚你并不能完全弄明白它。但你还是要继续前进。</p>
<p>顺便说一句，我希望我们有一个比“泛型”更好的术语，它起源于表示一种不同的数据结构中心多态风格。“参数多态”是Go提供的该功能的正确术语，这是一个准确的术语，但它难听。于是我们依然说“泛型”，尽管它不太恰当。</p>
<h2>编译器</h2>
<p>困扰编程语言社区的一件事是，早期的Go编译器是用C语言编写的。在他们看来，正确的方式是使用LLVM或类似的工具包，或者用Go语言本身编写编译器，这称为自举。我们没有做这两者中的任何一种，原因有几个。</p>
<p>首先，自举一种新语言要求至少其编译器的第一步必须用现有语言完成。对我们来说，C语言是显而易见的选择，因为Ken已经编写了C编译器，并且其内部结构可以很好地作为Go编译器的基础。此外，用自己的语言编写编译器，同时开发该语言，往往会产生一种适合编写编译器的语言，但这不是我们想要的语言。</p>
<p>早期的编译器工作良好，它可以很好地引导语言。但从某种意义上说，它有点奇怪，实际上它是一个Plan 9风格的编译器，使用旧的编译器编写思想，而不是新的思想，如<a href="https://tonybai.com/2022/10/21/understand-go-ssa-by-example/">静态单一赋值(SSA)</a>。生成的代码平庸，内部不太漂亮。但它是务实高效的，编译器代码本身体积适中，对我们来说也很熟悉，这使得我们在尝试新想法时可以快速进行更改。一个关键步骤是添加自动增长的分段堆栈。这很容易添加到我们的编译器中，但是如果我们使用像LLVM这样的工具包，考虑到ABI和垃圾收集器支持所需的更改，将这种更改集成到完整的编译器套件中是不可行的。</p>
<p>另一个工作良好的区域是交叉编译，这直接来自原始Plan 9编译器套件的工作方式。</p>
<p>按照我们的方式行事，无论多么非正统，都有助于我们快速前进。有些人对这一选择感到冒犯，但这对当时的我们来说是正确的选择。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-30.png" alt="" /><br />
<center>Go 1.5之后的Go编译器架构</center></p>
<p>对于Go 1.5版本，Russ Cox编写了一个工具，可以半自动将编译器从C转换为Go。到那时，语言已经完成，编译器导向的语言设计的担忧也就无关紧要了。有一些关于这个过程的在线演讲值得一看。我在2016年的GopherCon上做了一个关于汇编器的演讲，这在我毕生追求可移植性的过程中是一个高点。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-31.png" alt="" /><br />
<center>Go汇编器设计(GopherCon 2016) </center></p>
<p>我们从C开始做了正确的事情，但最终将编译器翻译为Go，使我们能够将Go所具有的所有优势带到其开发中，包括测试、工具、自动重写、性能分析等。当前的编译器比原始编译器干净得多，并且可以生成更好的代码。但是，当然，这就是自举的工作原理。</p>
<p>请记住，我们的目标不仅仅是一种语言，而是更多。</p>
<p>我们不寻常的做法绝不是对LLVM或语言社区中任何人的侮辱。我们只是使用了最适合我们任务的工具。当然，今天有一个LLVM托管的Go编译器，以及许多其他应该有的编译器。</p>
<h2>项目管理</h2>
<p>我们从一开始就知道，要成功，Go必须是一个开源项目。但我们也知道，在弄清楚关键的思想和有一个工作的实现之前，私下开发会更高效。头两年对澄清我们在试图实现什么，而不受干扰，是必不可少的。</p>
<p>向开源的转变是一个巨大的改变，也很具教育意义。来自社区的投入是压倒性的。与社区的接触花费了大量的时间和精力，尤其是对Ian，不知怎么他找到时间来回答任何人提出的每一个问题。但它也带来了更多。我仍然惊叹在Alex Brainman的指导下，社区完全独立完成的Windows移植的速度。那很神奇。</p>
<p>我们花了很长时间来理解转向开源项目的影响，以及如何管理它。</p>
<p>特别是，公平地说，我们花了太长时间来理解与社区合作的最佳方式。本次演讲的一个主题是我们的沟通不足——即使我们认为我们正在进行良好沟通——由于误解和不匹配的期望，大量时间被浪费了。本可以做得更好。</p>
<p>但是，随着时间的推移，我们说服了社区中的至少那一部分和我们在一起的人，我们的一些想法，虽然与常见的开源方式不同，但具有价值。最重要的是<strong>我们坚持通过强制代码审查和对细节的穷尽关注来维护高质量代码</strong>。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-32.png" alt="" /><br />
<center>Mission Control (drawing by Renee French) </center></p>
<p>一些项目的工作方式不同，它们快速接受代码，然后在提交后进行清理。Go项目则相反，力图将质量放在第一位。我相信这是更有效的方式，但它将更多的工作推回社区，如果他们不理解其价值，他们就不会感到应有的欢迎。在这方面还有很多东西要学习，但我相信现在的情况已经好多了。</p>
<p>顺便说一句，有一个历史细节不是广泛为人知的。该项目使用过4个不同的内容管理系统：SVN、Perforce、Mercurial和Git。Russ Cox做了一份艰巨的工作，保留了所有历史，所以即使今天，Git仓库也包含了在SVN中做出的最早的更改。我们都认为保留历史很有价值，我要感谢他做了这项艰苦的工作。</p>
<p>还有一点。人们经常认为谷歌会告诉Go团队该做什么。这绝对不是真的。谷歌对Go的支持非常慷慨，但它不制定议程。社区的投入要大得多。谷歌内部有一个巨大的Go代码库，团队用它来测试和验证版本，但这是通过从公共仓库导入谷歌完成的，而不是反过来。简而言之，核心Go团队由谷歌支付薪水，但他们是独立的。</p>
<h2>包管理</h2>
<p>Go的包管理开发过程做得并不好。我相信，语言本身的包设计非常出色，并且在我们讨论的第一年左右的时间里消耗了大量的时间。如果你感兴趣的话，我之前提到的SPLASH演讲详细解释了它为什么会这样工作。</p>
<p>一个关键点是使用纯字符串来指定导入语句中的路径，从而提供了我们正确认为很重要的灵活性。但从只有一个“标准库”到从网络导入代码的转变是坎坷的。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-33.png" alt="" /><br />
<center>修复云（Renee French 绘制）</center></p>
<p>有两个问题。</p>
<p>首先，我们这些Go核心团队的成员很早就熟悉Google的工作方式，包括它的monorepo(单一代码仓库)和每个人都在负责构建。但是我们没有足够的经验来使用具有大量包版本的包管理器以及尝试解决依赖关系图的非常困难的问题。直到今天，很少有人真正理解技术的复杂性，但这并不能成为我们未能从一开始就解决这些问题的借口。这尤其令人尴尬，因为我曾是一个失败项目的技术负责人，为谷歌的内部构建做类似的事情，我应该意识到我们面临的是什么。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-34.png" alt="" /><br />
<center>deps.dev</center></p>
<p>我在deps.dev上的工作是一种忏悔。</p>
<p>其次，让社区参与帮助解决依赖管理问题的初衷是好的，但当最终设计出来时，即使有大量的文档和有关理论的文章，社区中的许多人仍然感到受到了轻视。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-35.png" alt="" /><br />
<center>pkg.go.dev</center></p>
<p>这次失败给团队上了一课，让他们知道如何真正与社区互动，并且自此取得了很大的进步。</p>
<p>不过，现在事情已经解决了，新的设计在技术上非常出色，并且似乎对大多数用户来说效果很好。只是时间太长，而且道路崎岖不平。</p>
<h2>文档和示例</h2>
<p>我们事先没有得到的另一件事是文档。我们写了很多文档，并认为我们做得很好，但很快就发现社区想要的文档级别与我们的预期不同。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-36.png" alt="" /><br />
<center>修理图灵机的Gopher（Renee French 绘图）</center></p>
<p>关键缺失的一部分是最简单函数的示例。我们曾以为只需说明某个东西的功能就足够了，但我们花费了太长时间才接受到展示如何使用它的价值更大。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-37.png" alt="" /><br />
<center>可执行的例子</center></p>
<p>不过，我们已经吸取了教训。现在文档中有很多示例，大部分是由开源贡献者提供的。我们很早就做的一件事就是让它们在网络上可执行。我在2012年的Google I/O大会上做了一次演讲，展示了并发的实际应用，Andrew Gerrand 编写了一段可爱的Web goo，使得直接从浏览器运行代码片段成为可能。我怀疑这是第一次这样做，但Go是一种编译语言，很多观众以前从未见过这个技巧。然后该技术被部署到博客和在线包文档中。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-38.png" alt="" /><br />
<center>Go playground</center></p>
<p>也许更重要的是我们对Go Playground的支持，这是一个免费的开放沙箱，供人们尝试，甚至开发代码。</p>
<h2>结论</h2>
<p>我们已经走了很长一段路。</p>
<p>回顾过去，很明显很多事情都做得对，并且它们都帮助Go取得了成功。但还有很多事情可以做得更好，重要的是要承认这些问题并从中学习。对于任何托管重要开源项目的人来说，双方都有教训。</p>
<p>我希望我对这些教训及其原因的历史回顾会有所帮助，也许可以作为对那些反对我们正在做的事情和我们如何做的人的一种道歉/解释。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-39.png" alt="" /><br />
<center>GopherConAU 2023 吉祥物，作者：Renee French</center></p>
<p>但在推出 14 年后，我们终于来了。公平地说，总的来说这是一个非常好的地方。</p>
<p>很大程度上是因为通过设计和开发Go作为一种编写软件的方式（而不仅仅是作为一种编程语言）做出的决定，我们已经到达了一个新的地方。</p>
<p>我们到达这里的部分原因包括：</p>
<ul>
<li>一个强大的标准库，可实现服务器代码所需的大部分基础知识</li>
<li>并发作为该语言的“一等公民”</li>
<li>基于组合而不是继承的方法</li>
<li>澄清依赖管理的打包模型</li>
<li>集成的快速构建和测试工具</li>
<li>严格一致的代码格式</li>
<li>注重可读性而非聪明性</li>
<li>兼容性保证</li>
</ul>
<p>最重要的是，得益于令人难以置信的乐于助人且多元化的Gophers社区的支持。</p>
<p><img src="https://tonybai.com/wp-content/uploads/what-we-got-right-what-we-got-wrong-40.png" alt="" /><br />
<center>多元化的社区（@tenntennen 绘图）</center></p>
<p>也许这些问题最有趣的结果是，无论是谁编写的Go代码的外观和工作原理都是一样的，基本上没有使用该语言的不同子集的派系，并且保证随着时间的推移代码可继续编译和运行。对于主要编程语言来说，这可能是第一次。</p>
<p>我们绝对做对了。</p>
<p>谢谢。</p>
<hr />
<p><a href="https://public.zsxq.com/groups/51284458844544">“Gopher部落”知识星球</a>旨在打造一个精品Go学习和进阶社群！高品质首发Go技术文章，“三天”首发阅读权，每年两期Go语言发展现状分析，每天提前1小时阅读到新鲜的Gopher日报，网课、技术专栏、图书内容前瞻，六小时内必答保证等满足你关于Go语言生态的所有需求！2024年，Gopher部落将进一步聚焦于如何编写雅、地道、可读、可测试的Go代码，关注代码质量并深入理解Go核心技术，并继续加强与星友的互动。欢迎大家加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-tribe-zsxq-small-card.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/go-programming-from-beginner-to-master-qr.png" alt="img{512x368}" /></p>
<p><img src="http://image.tonybai.com/img/tonybai/go-first-course-banner.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/imooc-go-column-pgo-with-qr.jpg" alt="img{512x368}" /></p>
<p>著名云主机服务厂商DigitalOcean发布最新的主机计划，入门级Droplet配置升级为：1 core CPU、1G内存、25G高速SSD，价格5$/月。有使用DigitalOcean需求的朋友，可以打开这个<a href="https://m.do.co/c/bff6eed92687">链接地址</a>：https://m.do.co/c/bff6eed92687 开启你的DO主机之路。</p>
<p>Gopher Daily(Gopher每日新闻) &#8211; https://gopherdaily.tonybai.com</p>
<p>我的联系方式：</p>
<ul>
<li>微博(暂不可用)：https://weibo.com/bigwhite20xx</li>
<li>微博2：https://weibo.com/u/6484441286</li>
<li>博客：tonybai.com</li>
<li>github: https://github.com/bigwhite</li>
<li>Gopher Daily归档 &#8211; https://github.com/bigwhite/gopherdaily</li>
</ul>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。</p>
<p style='text-align:left'>&copy; 2024, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2024/01/07/what-we-got-right-what-we-got-wrong/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>2023年Go语言盘点：稳中求新，稳中求变</title>
		<link>https://tonybai.com/2023/12/31/the-2023-review-of-go-programming-language/</link>
		<comments>https://tonybai.com/2023/12/31/the-2023-review-of-go-programming-language/#comments</comments>
		<pubDate>Sun, 31 Dec 2023 05:27:21 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[2023]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[arena]]></category>
		<category><![CDATA[Arrow]]></category>
		<category><![CDATA[Camel]]></category>
		<category><![CDATA[ChatGPT]]></category>
		<category><![CDATA[clear]]></category>
		<category><![CDATA[comparable]]></category>
		<category><![CDATA[coverage]]></category>
		<category><![CDATA[devlake]]></category>
		<category><![CDATA[dubbo]]></category>
		<category><![CDATA[forrange]]></category>
		<category><![CDATA[gemini]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[Githut]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[go.mod]]></category>
		<category><![CDATA[go1.20]]></category>
		<category><![CDATA[go1.21]]></category>
		<category><![CDATA[GODEBUG]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[gomodule]]></category>
		<category><![CDATA[gonew]]></category>
		<category><![CDATA[gopherchina]]></category>
		<category><![CDATA[GopherCon]]></category>
		<category><![CDATA[gorilla]]></category>
		<category><![CDATA[govulncheck]]></category>
		<category><![CDATA[IEEE]]></category>
		<category><![CDATA[index]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[LLM]]></category>
		<category><![CDATA[loopvar]]></category>
		<category><![CDATA[max]]></category>
		<category><![CDATA[min]]></category>
		<category><![CDATA[mux]]></category>
		<category><![CDATA[ollama]]></category>
		<category><![CDATA[panic]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[PGO]]></category>
		<category><![CDATA[PYPL]]></category>
		<category><![CDATA[redmonk]]></category>
		<category><![CDATA[RobPike]]></category>
		<category><![CDATA[RussCox]]></category>
		<category><![CDATA[SDK]]></category>
		<category><![CDATA[slog]]></category>
		<category><![CDATA[Spectrum]]></category>
		<category><![CDATA[sync]]></category>
		<category><![CDATA[Telemetry]]></category>
		<category><![CDATA[Tesla]]></category>
		<category><![CDATA[TIOBE]]></category>
		<category><![CDATA[unsafe]]></category>
		<category><![CDATA[v2]]></category>
		<category><![CDATA[wasi]]></category>
		<category><![CDATA[wasm]]></category>
		<category><![CDATA[zap]]></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>
		<category><![CDATA[远控]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=4092</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2023/12/31/the-2023-review-of-go-programming-language 时光荏苒，转眼间已经是2023年的最后一天了。《2022年Go语言盘点：泛型落地，无趣很好，稳定为王》仿佛就写在昨天。 回首这一年，全球彻底从新冠大流行中得以复苏，Go语言也不例外，最直观的表现就是全球各地的GopherCon技术大会或小型Meetup都纷纷从停办/线上的状态来到了线下，并获得Gopher们的热烈欢迎和踊跃参与，比如下图中的GopherCon、GopherCon UK、GopherCon Europe、GopherCon Australia、Golab等。 尤其值得一提的是我们本土最大的Gopher技术大会GopherChina 2023，今年为了满足不同地域Gopher的需求，GoCN社区在6月和11月分别在北京和上海举办了两次GopherChina大会，这也是历史首次。 Go语言团队的大神们也开始重新“乐此不疲”地参与到上述这些大会中，以推进全球Go社区与生态的建设。就连已经退居二线的Go语言之父Rob Pike也亲自“现身说法”，在年底的GopherCon Australia 2023上发表了“What We Got Right, What We Got Wrong”的主题演讲来回顾Go诞生以来的得与失。 大神回顾一生，我们盘点一年。在这篇文章中，我就和大家一起聊聊Go在2023年的状态、所处的位置以及Go未来演进的机制与策略。 1. Go的2023 1.1 稳 一如往年，Go在2023年发布了两个大版本，分别是2023年2月份的Go 1.20和8月份的Go 1.21。 在这两个版本中，Go语法特性一如既往的求稳，除了支持切片类型到数组类型(或数组类型的指针)的类型转换，其余更是像语法的修修补补，比如：comparable“放宽”了对泛型实参的限制、unsafe包继续添加“语法糖”、增加min、max和clear预定义函数、增强type inference能力等。 这些并不会让Gopher感到“意外”，因为这与Russ Cox在2022年宣称的“Go is boring”的精神是一脉相承的。 不过，除了Go语法特性变化方面的“寡淡”之外，Go在其他方面还是求新和求变的，接下来我们先来看看Go是如何求新的。 注：求新与求变可能存在交集的地方，边界可能也有一定模糊性，也存在相互促进的情况，希望大家阅读下面内容时不要吹毛求疵:)。 1.2 求新 Go在语法特性求稳的同时，在编译器、工具链、运行时以及标准库等方面都在努力优化和打磨，旨在进一步提升Go兼具的生产力与运行时效率，其中很多优化和打磨的措施不乏新颖。 Go 1.20版本中首次引入的PGO(profile-guided optimization)技术预览版，到Go 1.21版本变为默认开启，Go官方给出的PGO优化的效果数据是：PGO优化带来的性能提升一般是2%~7%，而在最新的Go 1.22rc1中，这个数字已经变为2%~14%了。 在内存管理方面，Go 1.20引入了试验特性arena包，虽然它没能在Go 1.21中按时转正，如今处于proposal-hold状态，但这也算是一次在内存管理机制上的求新。 Go是一门面向软件工程的编程语言，在这一年中，Go在软件工程领域的求新例子也是不少。比如：可用于大幅简化Go项目创建的gonew工具，它支持基于go project template clone并创建一个属于你的Go项目；再比如对应用执行时的代码覆盖率的采集，可以帮助开发者更进一步了解最终可执行程序代码执行路径上的测试覆盖情况；而govulncheck工具则是Go在软件工程与供应链安全领域的求新尝试，该工具丰富了我们对Go项目进行安全漏洞检查的手段。 注：关于供应链安全问题，Russ Cox近期有一个专门的Talk：Open Source [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/the-2023-review-of-go-programming-language-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2023/12/31/the-2023-review-of-go-programming-language">本文永久链接</a> &#8211; https://tonybai.com/2023/12/31/the-2023-review-of-go-programming-language</p>
<p>时光荏苒，转眼间已经是2023年的最后一天了。《<a href="https://tonybai.com/2022/12/29/the-2022-review-of-go-programming-language">2022年Go语言盘点：泛型落地，无趣很好，稳定为王</a>》仿佛就写在昨天。</p>
<p>回首这一年，全球彻底从新冠大流行中得以复苏，Go语言也不例外，最直观的表现就是<strong>全球各地的GopherCon技术大会或小型Meetup都纷纷从停办/线上的状态来到了线下</strong>，并获得Gopher们的热烈欢迎和踊跃参与，比如下图中的<a href="https://www.gophercon.com/">GopherCon</a>、<a href="https://www.gophercon.co.uk/">GopherCon UK</a>、<a href="https://gophercon.eu/">GopherCon Europe</a>、<a href="https://gophercon.com.au/">GopherCon Australia</a>、<a href="https://golab.io/">Golab</a>等。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2023-review-of-go-programming-language-2.png" alt="" /></p>
<p>尤其值得一提的是我们本土最大的Gopher技术大会<a href="https://mp.weixin.qq.com/s?__biz=MzIyNzM0MDk0Mg==&amp;mid=2247494867&amp;idx=1&amp;sn=9bf0dfa3ef48867da891aac4359a0c5e&amp;chksm=e8600b32df178224428d5ee27fd11e379011afc0bdb7e0445617275c4c43c484f72200b585dc#rd">GopherChina 2023</a>，今年为了满足不同地域Gopher的需求，GoCN社区在6月和11月分别在北京和上海举办了两次GopherChina大会，这也是历史首次。</p>
<p>Go语言团队的大神们也开始重新“乐此不疲”地参与到上述这些大会中，以推进全球Go社区与生态的建设。就连已经退居二线的<a href="https://tonybai.com/2023/12/11/simplicity/">Go语言之父Rob Pike</a>也亲自“现身说法”，在年底的GopherCon Australia 2023上发表了“What We Got Right, What We Got Wrong”的主题演讲来回顾Go诞生以来的得与失。</p>
<p>大神回顾一生，我们盘点一年。在这篇文章中，我就和大家一起聊聊Go在2023年的状态、所处的位置以及Go未来演进的机制与策略。</p>
<h2>1. Go的2023</h2>
<h3>1.1 稳</h3>
<p>一如往年，Go在2023年发布了两个大版本，分别是2023年2月份的<a href="https://tonybai.com/2023/02/08/some-changes-in-go-1-20/">Go 1.20</a>和8月份的<a href="https://tonybai.com/2023/08/20/some-changes-in-go-1-21">Go 1.21</a>。</p>
<p>在这两个版本中，Go语法特性一如既往的求稳，除了支持<strong>切片类型到数组类型(或数组类型的指针)的类型转换</strong>，其余更是像语法的修修补补，比如：comparable“放宽”了对泛型实参的限制、unsafe包继续添加“语法糖”、增加min、max和clear预定义函数、增强type inference能力等。</p>
<p>这些并不会让Gopher感到“意外”，因为这与<a href="https://tonybai.com/2022/12/29/the-2022-review-of-go-programming-language">Russ Cox在2022年宣称的“Go is boring”</a>的精神是一脉相承的。</p>
<p>不过，除了Go语法特性变化方面的“寡淡”之外，Go在其他方面还是求新和求变的，接下来我们先来看看Go是如何求新的。</p>
<blockquote>
<p>注：求新与求变可能存在交集的地方，边界可能也有一定模糊性，也存在相互促进的情况，希望大家阅读下面内容时不要吹毛求疵:)。</p>
</blockquote>
<h3>1.2 求新</h3>
<p>Go在语法特性求稳的同时，在编译器、工具链、运行时以及标准库等方面都在努力优化和打磨，旨在进一步提升Go兼具的生产力与运行时效率，其中很多优化和打磨的措施不乏新颖。</p>
<p><a href="https://go.dev/blog/pgo-preview">Go 1.20版本中首次引入的PGO(profile-guided optimization)技术预览版</a>，到Go 1.21版本变为默认开启，Go官方给出的PGO优化的效果数据是：PGO优化带来的性能提升一般是2%~7%，而在<a href="https://tonybai.com/2023/12/25/go-1-22-foresight">最新的Go 1.22rc1</a>中，这个数字已经变为2%~14%了。</p>
<p>在内存管理方面，<a href="https://github.com/golang/go/issues/51317">Go 1.20引入了试验特性arena包</a>，虽然它没能在Go 1.21中按时转正，如今处于proposal-hold状态，但这也算是一次在内存管理机制上的求新。</p>
<p>Go是一门面向软件工程的编程语言，在这一年中，Go在软件工程领域的求新例子也是不少。比如：可用于大幅简化Go项目创建的<a href="https://tonybai.com/2023/08/11/introduction-to-the-gonew-tool">gonew</a>工具，它支持基于go project template clone并创建一个属于你的Go项目；再比如<a href="https://go.dev/blog/integration-test-coverage">对应用执行时的代码覆盖率的采集</a>，可以帮助开发者更进一步了解最终可执行程序代码执行路径上的测试覆盖情况；而<a href="https://tonybai.com/2022/09/10/an-intro-of-govulncheck">govulncheck工具</a>则是Go在软件工程与<a href="https://tonybai.com/2022/03/14/software-supply-chain-security-in-go">供应链安全</a>领域的求新尝试，该工具丰富了我们对Go项目进行安全漏洞检查的手段。</p>
<blockquote>
<p>注：关于供应链安全问题，Russ Cox近期有一个专门的Talk：<a href="https://research.swtch.com/acmscored">Open Source Supply Chain Security at Google</a>，感兴趣的童鞋可以学习一下。</p>
</blockquote>
<p>Go始终对IT界出现的新技术、新趋势以及Go社区的新想法保持open。在WASM出现早期，<a href="https://tonybai.com/2018/11/19/some-changes-in-go-1-11/">Go就提供了对wasm的porting支持</a>，如今在Go 1.21中，Go还对尚未形成最终规范的<a href="https://go.dev/blog/wasi">WASI(WebAssembly System Interface)</a>提供了支持。</p>
<p>Go社区的反馈也是Go团队求新的来源，比如一个典型例子就是<a href="https://tonybai.com/2023/09/01/slog-a-new-choice-for-logging-in-go">log/slog加入标准库</a>，让Go标准库原生支持了结构化日志输出，且日志性能不输<a href="https://tonybai.com/2021/07/14/uber-zap-advanced-usage">像zap这样的第三方开源log包</a>。</p>
<p>Go社区也跟随Go团队的节奏，走在求新的道路上。2023年，IT界最大的事件就是<strong>以ChatGPT为代表的大语言模型的横空出世</strong>，这很可能是一个百年不遇的、对人类文明进步有着重要里程碑意义的事件。各行各业，言必称大模型，言必称AI。在传统机器学习、深度学习以及<a href="https://tonybai.com/2023/05/21/go-and-nn-part1-tensor-operations">神经网络</a>方面生态并不丰富的Go，也在尝试与大模型对接，比如：支持快速在本地启动和运行llama2、mistral 7B、codellama、vicuna等大模型的<a href="https://github.com/jmorganca/ollama">ollama开源项目</a>在短短几个月就收获近30k个小星星的关注；再比如Gemini大模型推出后，Google一并开源了支持与Google各种大模型项目对接的<a href="https://github.com/google/generative-ai-go">Google AI Go SDK开源项目</a>，并提供了详细的教程<a href="https://ai.google.dev/tutorials/go_quickstart?hl=zh-cn">指导Gopher如何通过该SDK与大模型交互</a>。</p>
<blockquote>
<p>注：Google把Gemini Pro的API免费提供给个人用户了，该模型具备GPT 3.5 级别的能力，32k 上下文，38 种语言支持以及多模态支持，唯一的约束是每分钟60个请求。</p>
</blockquote>
<p>在<a href="https://go.dev/blog/survey2023-h2-results">2023年第二次Go用户调查报告</a>中，Go 开发者表示，他们对改善其编写代码的质量、可靠性和性能的人工智能/机器学习工具感兴趣，而不是编写代码的工具。一位时刻警醒、从不忙碌的专家“审阅者”可能是一种更有帮助的AI开发者辅助形式。Go官方表示了对该调查结果的重视，也许在后续的Go工具链中“AI加持”会成为常态。</p>
<h3>1.3 求变</h3>
<p>2023年8月，在Go 1.21版本刚刚发布后，Go官博就发布了Russ Cox编写的两篇文章：《<a href="https://go.dev/blog/compat">Backward Compatibility, Go 1.21, and Go 2</a>》和《<a href="https://go.dev/blog/toolchain">Forward Compatibility and Toolchain Management in Go 1.21</a>》，进一步明确了Go承诺的向后兼容的范围和方案，并<a href="https://tonybai.com/2023/09/10/understand-go-forward-compatibility-and-toolchain-rule/">第一次阐述了向前兼容性的具体方案</a>，这两篇文章为Go语言后续的“求变”奠定了理论基础。</p>
<p>在向后兼容方面，从Go 1.21开始Russ Cox提出一些举措，比如：Go将扩展和规范化了GODEBUG的使用，其大致思路如下：</p>
<ul>
<li>对于每个在Go1兼容性承诺范围内的且可能会破坏(break)现有代码的新特性/新改变(比如：panic(nil)语义的改变)加入时，Go会向GODEBUG设置<br />
中添加一个新选项(比如GODEBUG=panicnil=1)，以保留采用原语义进行编译的兼容能力；</li>
<li>GODEBUG中新增的选项将至少保留两年(4个Go release版本)，对于一些影响重大的GODEBUG选项(比如http2client和http2server)，保留的时间可能更长，甚至一直保留；</li>
<li>GODEBUG的选项设置与go.mod的go version是匹配的。例如，即便你现在的工具链是Go 1.21，如果go.mod中的go version为1.20，那么GODEBUG控制的新特性语义将不起作用，依旧保持Go 1.20时的行为。除非你将go.mod中的go version升级为go 1.21.0；</li>
<li>在Go 1.21及以后版本中，除了可以使用像GODEBUG=panicnil=1的环境变量恢复原先语义外，还可以在main包中使用//go:debug指示符。</li>
</ul>
<p>在向前兼容方面，Russ Cox提出的方案有些复杂难懂，这里就不赘述了，感兴趣的童鞋可以阅读一下我之前的文章《<a href="https://tonybai.com/2023/09/10/understand-go-forward-compatibility-and-toolchain-rule/">聊聊Go语言的向前兼容性和toolchain规则</a>》了解更多细节。</p>
<h4>1.3.1 语法填坑</h4>
<p>在Go的诸多“求变”中，影响最大的还是对已有语法坑的“修正”，这些“填坑”工作或多或少都会对存量代码带去影响，甚至是break change，Go社区的反对声音也是不少。但无论怎样，这些工作已经在Go 1.21版本拉开帷幕了。比如：改变panic(nil)的语义以及对<a href="https://go.dev/blog/loopvar-preview">循环变量语义的变更</a>，大家可以在《<a href="https://tonybai.com/2023/08/20/some-changes-in-go-1-21/">Go 1.21中值得关注的几个变化</a>》一文中了解更多细节。</p>
<p>对现有语法坑的修正也进一步促进了“求新”，比如在修正loopvar语义的同时，for range支持对更多类型表达式的迭代也在进行中，比如Go 1.22中，<a href="https://tonybai.com/2023/12/25/go-1-22-foresight/">for range将支持迭代整型表达式</a>，并以试验特性提供了对函数迭代器的支持。</p>
<h4>1.3.2 标准库v2示范</h4>
<p>Go号称是“自带电池”的语言，其高质量的标准库得到了广大Gopher的欢迎。Go团队也一直努力推进Go标准库功能的丰富性，比如：Go 1.22中对http.ServeMux功能进行了增强，使其像第三方的gorilla/mux那样增加对带有通配符路由的匹配。</p>
<p><a href="https://tonybai.com/2023/12/25/go-1-22-foresight/">Go 1.22中，标准库还首次出现了v2版本包：math/rand/v2</a>，这为后续标准库的vN方式演进提供了示范，从Go团队的官方issue、discussion中了解到，后续如sync/v2、encoding/json/v2等已经列上日程了。</p>
<h2>2. Go所处的位置</h2>
<p>很多人关注Go当前的状态：国内大厂用的多么？小厂是不是也在广泛采纳。这些问题我在往年的Go语言盘点时也都做过梳理，今年就不再提了。没有哪个大厂在广泛采用一门语言后，会在一年内全部推翻重写的；小厂对Go的采纳也是有惯性的。</p>
<p>今年先从我的两个意外“收获”开始。</p>
<h3>2.1 两个意外的“收获”</h3>
<p>2023年10月中旬，世界知名电动车厂商Tesla发布了<a href="https://developer.tesla.com/docs/fleet-api">新版fleet API</a>和<a href="https://github.com/teslamotors/vehicle-command">vehicle command SDK</a>，鉴于本人也在智能网联汽车行业内打拼，于是对Tesla的此次发布做了一些深入了解。在Tesla的github主页上我赫然发现：Go是目前Tesla开源项目的第二大语言。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2023-review-of-go-programming-language-3.png" alt="" /></p>
<p>相对于传统的主机厂(车厂)，Telsa算是比较开放的了。开放包含两个含义，一是将车端能力的开放，二是项目的开源。就目前了解到，国内主机厂还鲜有将车端能力开放出来的，开源就更是鲜见。但Tesla在这两方面都做到了，既开放了车端API，又做了针对性的开源，虽然目前其开源项目并不多。以前Tesla涉及到云端服务的项目多用<a href="">Ruby</a>，但从2022年开始，Go语言的使用逐渐增多，包括前面提到的Fleet API的<a href="https://github.com/teslamotors/fleet-telemetry">Fleet Telemetry的参考server实现</a>以及<a href="https://github.com/teslamotors/vehicle-command">Tesla车辆远控SDK</a>。</p>
<p>我们再来看看Apache基金会。众所周知，Apache基金会的开源项目多以Java语言为主，但一次偶然的机会翻看Apache基金会的github项目主页，我发现Go语言在Apache开源项目中已经悄悄地跻身到第五名，如果仅算后端语言的话，Go排名第三，仅次于Java和Python。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2023-review-of-go-programming-language-4.png" alt="" /></p>
<p>并且，Apache基金会下面的Go项目实际也不少，大家可以通过https://github.com/orgs/apache/repositories?language=go&amp;type=all查询。其中还不乏优秀之作，比如：<a href="https://github.com/apache/incubator-answer">构建Q&amp;A知识系统的answer</a>、<a href="https://github.com/apache/dubbo-go">Apache Dubbo的go实现dubbo-go</a>、<a href="https://github.com/apache/trafficcontrol">CDN实现trafficcontrol</a>、<a href="https://github.com/apache/camel-k">Kubernetes原生的轻量级企业应用集成框架Camel K</a>、<a href="https://tonybai.com/2023/06/25/a-guide-of-using-apache-arrow-for-gopher-part1">Apache Arrow的Go实现</a>以及<a href="https://github.com/apache/incubator-devlake">针对开发过程的聚合数据平台devlake</a>等。</p>
<p>我们知道：Apache项目在企业级应用和平台方面具有广泛的应用，从Go语言在Apache基金会项目中的使用比例的提升现象来看，Go在企业应用市场中的普及度和受欢迎程度确实有所增长。</p>
<h3>2.2 Go语言排名</h3>
<p>编程语言之间的竞争与争议，通常被称为“编程语言战争”(programming language war)，它其实反映了不同技术群体和范式之间的碰撞。这些“火药味”比较浓的语言之争通常比较主观。近10年来，业界出现了一些被广泛接受的编程语言排行榜，它们基于一些相对客观的数据来反映不同编程语言在现实开发中的真实状态。但不同编程语言排行榜都有不同的数据来源和数据模型，单一的排行榜往往是“盲人摸象”，无法反映全貌。但目前又没有一个可以让我们一窥全貌的权威排行榜。因此，要想更客观地、更全面的反映一门编程语言的实际情况，我们需要将多个排行榜参照着看。</p>
<p>下面我们就来看看在目前世界上著名的编程语言排行榜上，Go语言在其中的最新排名情况(请注意：各个榜单的发布时间不同，导致各榜单的数据会有一定时间差)。</p>
<h4>2.2.1 <a href="https://pypl.github.io/PYPL.html">PYPL编程语言排行榜</a></h4>
<p>PYPL编程语言流行指数是通过分析语言教程在谷歌上的搜索频率而创建的。语言教程被搜索的次数越多，说明该语言越受欢迎，原始数据来自Google Trends：</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2023-review-of-go-programming-language-5.png" alt="" /><br />
<center>PYPL编程语言排行榜，数据时间：2023.12</center></p>
<h4>2.2.2 <a href="https://spectrum.ieee.org/the-top-programming-languages-2023">IEEE Spectrum排行榜</a></h4>
<p>IEEE Spectrum排行榜是通过调查来自全球软件工程师和招聘网站的数据，统计各语言的流行度的：</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2023-review-of-go-programming-language-6.png" alt="" /><br />
<center>IEEE Spectrum排行榜，数据时间：2023.8</center></p>
<h4>2.2.3 <a href="https://redmonk.com/sogrady/2023/05/16/language-rankings-1-23/">RedMonk编程语言排行榜</a></h4>
<p>RedMonk排行榜是根据GitHub和Stack Overflow这两个开发者社区上的讨论数量来推算语言的受关注度。</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2023-review-of-go-programming-language-7.png" alt="" /><br />
<center>RedMonk编程语言排行榜，数据时间：2023.5</center></p>
<h4>2.3.4 <a href="https://github.blog/2023-11-08-the-state-of-open-source-and-ai/">Github Octoverse</a></h4>
<p>GitHub Octoverse排行榜直观反映了过去一年GitHub上各编程语言的实际使用和流行趋势，是从开源项目量的维度来衡量编程语言活跃度的。在Top 10语言榜单上，2023年Go超越Ruby第一次跻身Github Top10语言：</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2023-review-of-go-programming-language-8.png" alt="" /><br />
<center>Github Octoverse编程语言排行榜，数据时间：2023.11</center></p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2023-review-of-go-programming-language-9.png" alt="" /><br />
<center>Github Octoverse编程语言排行榜，数据时间：2023.11</center></p>
<h4>2.3.5 <a href="https://madnight.github.io/githut/">Github Language Stats(githut)</a></h4>
<p>Github Language Stats是一个个人项目，它基于github公开数据，按时间、pr数量、star数量等维度对各个语言在github上的使用情况进行分析：</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2023-review-of-go-programming-language-10.png" alt="" /><br />
<center>Githut按PR数量，数据时间：2023第三季度</center></p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2023-review-of-go-programming-language-11.png" alt="" /><br />
<center>Githut按Star数量，数据时间：2023第三季度</center></p>
<h4>2.3.6 <a href="https://www.tiobe.com/tiobe-index/">TIOBE编程语言排行榜</a></h4>
<p>TIOBE编程语言排行榜理论上来说，是世界上最知名的编程语言排行榜，它根据各大搜索引擎编程语言相关的搜索查询量来计算一个综合指数。但这些年TIOBE榜单数据的“上蹿下跳”，让开发者对该榜单是“又爱又恨”。下面是TIOBE index 2023年12月份的榜单：</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2023-review-of-go-programming-language-12.png" alt="" /></p>
<p>当你看到Fortran排在Go的前面，你就get到该榜单的抽风式的“不靠谱”了:)。</p>
<p>综合上述6个榜单，我们可以看到Go语言的2023基本处于稳定发展状态，没有“大踏步”的前进，也没有意想不到的大幅退步。</p>
<p>今年在国内某乎上总有一些有关“Go在国内是否已凉”的话题，从上面实际情况来看，话题中那些抹黑Go的观点可以不攻自破了。有人会说Rust的强势上升对Go会有一定冲击，这的确不可否认，就像Go当年火速蹿升给Java带去一定冲击一样，这是一门编程语言在演进阶段必会经历的过程，没有什么值得大惊小怪的。5年后，Rust可能同样也会受到来自其他语言的冲击。</p>
<p>Go语言未来会变得如何，关键还要看Go团队对Go未来演进方向的把握是否得当以及Go社区与生态是否给力。2023年，Go团队也明确了未来的演进机制和策略，接下来我们就来看看。</p>
<h2>3. Go的未来演进</h2>
<p>2023年是<a href="https://tonybai.com/2023/11/11/go-opensource-14-years/">Go语言开源的第14个年头</a>，Go语言早已蜕下了少年期的青涩，进入到了青年期。这意味着它拥有了越来越成熟稳定的语言特性，同时生态系统也日益丰富完善。作为一门青壮年语言，Go语言在系统设计方面展现出的高度工程化思想，使其轻松应对复杂系统的构建。以go module为主的模块化支持帮助大规模程序更加清晰化，丰富的并发控制手段使其可以处理海量请求。与此同时，Go语言生态也在蓬勃成长——各种高质量框架应运而生，无数module可复用，大量的云原生组件可供选择。这为开发者极大减轻了从零开始搭建系统的工作量。</p>
<p>和我们人类一样，一门语言进入青年期后的成熟特征并不能完全掩饰其未来演进的迷茫！在Ken Thompson、Rob Pike相继退休后，Russ Cox成为了Go这艘大船的“掌舵者”，Russ Cox与Go团队对编程语言的思考，对Go语言价值观的判断将直接决定Go未来的航向。</p>
<p>好在，在2023年的GopherCon大会上，我们得到了Russ Cox的答案：那就是<a href="https://tonybai.com/2023/12/10/go-changes/">基于共同目标和数据驱动的决策</a>。这里借用Russ Cox在演讲中给出的结论来看看具体的演进驱动机制：</p>
<ul>
<li>首先，Go需要不断变化，特别是随着计算世界的变化。</li>
<li>其次，任何改变的目标都是为了使Go在软件工程中变得更好，尤其是在规模化(scaling)方面。</li>
<li>第三，一旦我们确定了目标，达成共识的下一个最重要的部分是拥有共享数据来做出决策。</li>
<li>第四，Go工具链遥测是增补我们现有调查和代码分析数据的重要数据来源。</li>
</ul>
<p>综上来看，Go团队要“拥抱变化”，但不能“无头苍蝇”一样的胡乱改变，而是严谨地基于广泛的数据反馈，包括来自用户调查、vscode插件运行的用户反馈、全年进行的研究访谈和用户体验研究等，以及来自即将<a href="https://research.swtch.com/telemetry">加入Go工具链的可选遥测(opt-in Telemetry)功能</a>获取到的更多真实的Go使用数据。</p>
<p>相信在Go工具链的可选遥测(opt-in Telemetry)功能加入后，Go团队能基于这些用户数据拿到更准确地决策依据，继续让Go这艘大船行驶在正确、光明的航向上！</p>
<h2>4. 小结</h2>
<p>在2023年，Go语言继续保持了其稳定性和可靠性的特点。发布了两个大版本，Go 1.20和Go 1.21，其中语法特性的改变相对较少，注重修复和优化。然而，Go语言在其他方面仍然保持着求新和求变的态势。</p>
<p>Go语言团队致力于优化编译器、工具链、运行时和标准库，以提升生产力和运行时效率。引入了一些新的特性和优化措施，例如PGO（profile-guided optimization）技术的引入和优化、内存管理方面的改进等。同时，Go语言在软件工程领域也进行了一些创新，如简化项目创建的gonew工具、代码覆盖率的采集工具、供应链安全领域的govulncheck工具等。</p>
<p>Go语言始终保持对新技术、新趋势和社区的开放姿态。在2023年，Go语言对WASM和WASI的支持得到了进一步加强。同时，Go社区也积极响应并跟随Go团队的步伐，面对IT界出现的大语言模型等新兴技术，Go社区也在不断探索和应用。</p>
<p>总体而言，2023年对于Go语言来说是一个稳中求新、稳中求变的年份。Go语言保持着其简洁、高效和易用的特点，同时积极适应和采纳新的技术和需求，为开发者提供更好的开发体验和工具支持。</p>
<p>展望未来，Go团队已经明确了更加以共识和用户数据为驱动的演进机制，保证Go的发展方向与实际需求保持同步。随着可选的工具链遥测功能加入，相信他们能基于更丰富的用户数据做出更正确、更具预见性的正确决策。</p>
<p>我个人依旧坚持我之前的判断：<strong>Go将进入或已处于自己的黄金5-10年</strong>。</p>
<hr />
<p><a href="https://public.zsxq.com/groups/51284458844544">“Gopher部落”知识星球</a>旨在打造一个精品Go学习和进阶社群！高品质首发Go技术文章，“三天”首发阅读权，每年两期Go语言发展现状分析，每天提前1小时阅读到新鲜的Gopher日报，网课、技术专栏、图书内容前瞻，六小时内必答保证等满足你关于Go语言生态的所有需求！2023年，Gopher部落将进一步聚焦于如何编写雅、地道、可读、可测试的Go代码，关注代码质量并深入理解Go核心技术，并继续加强与星友的互动。欢迎大家加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-tribe-zsxq-small-card.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/go-programming-from-beginner-to-master-qr.png" alt="img{512x368}" /></p>
<p><img src="http://image.tonybai.com/img/tonybai/go-first-course-banner.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/imooc-go-column-pgo-with-qr.jpg" alt="img{512x368}" /></p>
<p>著名云主机服务厂商DigitalOcean发布最新的主机计划，入门级Droplet配置升级为：1 core CPU、1G内存、25G高速SSD，价格5$/月。有使用DigitalOcean需求的朋友，可以打开这个<a href="https://m.do.co/c/bff6eed92687">链接地址</a>：https://m.do.co/c/bff6eed92687 开启你的DO主机之路。</p>
<p>Gopher Daily(Gopher每日新闻) &#8211; https://gopherdaily.tonybai.com</p>
<p>我的联系方式：</p>
<ul>
<li>微博(暂不可用)：https://weibo.com/bigwhite20xx</li>
<li>微博2：https://weibo.com/u/6484441286</li>
<li>博客：tonybai.com</li>
<li>github: https://github.com/bigwhite</li>
<li>Gopher Daily归档 &#8211; https://github.com/bigwhite/gopherdaily</li>
</ul>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。</p>
<p style='text-align:left'>&copy; 2023, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2023/12/31/the-2023-review-of-go-programming-language/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Go未来演进：基于共同目标和数据驱动的决策</title>
		<link>https://tonybai.com/2023/12/10/go-changes/</link>
		<comments>https://tonybai.com/2023/12/10/go-changes/#comments</comments>
		<pubDate>Sun, 10 Dec 2023 13:07:00 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[append]]></category>
		<category><![CDATA[Compiler]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Go1]]></category>
		<category><![CDATA[go1.21]]></category>
		<category><![CDATA[go1.22]]></category>
		<category><![CDATA[gofmt]]></category>
		<category><![CDATA[goimports]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[gomodule]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[GopherCon]]></category>
		<category><![CDATA[gopls]]></category>
		<category><![CDATA[gorename]]></category>
		<category><![CDATA[govulncheck]]></category>
		<category><![CDATA[Go泛型]]></category>
		<category><![CDATA[loopvar]]></category>
		<category><![CDATA[panic]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[proposal]]></category>
		<category><![CDATA[RobertGriesemer]]></category>
		<category><![CDATA[RobPike]]></category>
		<category><![CDATA[RussCox]]></category>
		<category><![CDATA[Slice]]></category>
		<category><![CDATA[SoftwareEngineering]]></category>
		<category><![CDATA[sqlite]]></category>
		<category><![CDATA[sumdb]]></category>
		<category><![CDATA[Telemetry]]></category>
		<category><![CDATA[typeparameter]]></category>
		<category><![CDATA[vscode]]></category>
		<category><![CDATA[wasm]]></category>
		<category><![CDATA[workspace]]></category>
		<category><![CDATA[yaml]]></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=4069</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2023/12/10/go-changes 自从Go语言之父Rob Pike从Google退休并隐居澳洲后，Russ Cox便成为了Go语言团队的“带头大哥”，虽然其资历还无法与依旧奋战在一线的另外一位Go语言之父Robert Griesemer相比。如今，Russ Cox对Go语言未来的演化发展是很有“发言权”的，Go module的引入便是Russ Cox的重要决策之一。从Go社区来看，这些年来，以Russ Cox为首的Go团队对Go演进决策总体上是良性的、受欢迎的，比如Go module、Go泛型、Go对wasm的支持等，当然也有一些变化是受到质疑的，比如：Go 1.22版本很可能从试验特性到正式特性的loopvar等。 注：我的极客时间《Go语言第一课》专栏中有对Go module和Go泛型的详细讲解，欢迎感兴趣的童鞋订阅阅读。 想必很多Gopher也和我一样，对Go团队就某一proposal的决策方式和依据很好奇 &#8211;到底他们是如何决定是否accept这个proposal的？Go语言后续该如何演化？向哪个方向发展演化？ 今年9月份举办的GopherCon 2023上，Russ Cox代表Go团队做了名为“Go Changes”的主题演讲： 在这个talk中，我们能找到一些答案。近期他重新录制了该演讲视频，并在其个人博客中放出。 本文就是基于这个视频内容进行整理加工后的文字稿，供国内广大gopher参考。 这是我在2023年GopherCon上做的一次演讲的重新录制视频。在这次演讲中，我和大家分享了三部分内容：为什么Go需要随着时间的推移而改变，我们如何应对Go的变化过程，以及为什么选择性遥测(opt-in telemetry)是这个过程中的一个重要且适当的部分。不过，这个演讲不是关于某个特定的Go特性变化，而是关于Go整体的变化过程，特别是我们是如何决定做出哪些改变的。 首先一个明显的问题是，为什么Go需要改变? 为什么我们不能对Go感到满意，然后将其束之高阁呢? 一个显而易见的答案是我们不可能一次就把事情做对，你对比一下上面图片中展示的第一版毛绒Go吉祥物和我们在GopherCon上发放的最终版本，你就能明白我的意思了。 但这里还有一个更深层次的答案： 我的一位前同事在他使用了多年的邮件签名中引用了生物学家兼科幻小说作家杰克·科恩(Jack Cohen)的一句名言。在这句名言中，科恩说：“我们生物学家使用的一个描述‘稳定(stable)’的专业词汇就是“死(dead)”。 所有的生命都在变化，适应新的环境，修复损伤等。编程环境也需要改变。除非我们想要Go死掉，否则它需要适应新的环境，比如新的协议、操作系统和重要用例。我们也需要发现并修复bug &#8212; 语言、库和生态系统的问题，这些问题只有随着时间的推移或Go发展到一定阶段和规模才会暴露出来。 Go必须改变，并与时俱进。这次演讲就是关于我们如何决定做出哪些改变。 这次演讲分三个部分: 第一部分是关于我们对Go的愿景和期望。 第二部分是关于我们如何利用数据来决定做出哪些改变。 第三部分是关于我们在Go工具链中增加选择性遥测的计划，以便更好地理解Go的使用情况和出现问题的地方。 到演讲结束时，你将了解我们考量和决定Go变化的过程，并了解数据在做出这些决定中的重要性，我希望你能理解为什么选择性遥测是一个很好的额外数据来源，甚至可能愿意在系统推出时就选择加入。 让我们从这个开始：我们希望Go发生什么样的变化？如果我们在这个基本问题上意见不一致，我们也就无法就具体的变化达成共识。 例如，我们是否应该在Go中添加一个Perl语句，让我们可以用Perl编写函数? 我认为我们不应该，但假设你有不同意见。为了解决这个问题，我们需要理解为什么我们持不同意见。 约翰·奥斯特豪特(John Ousterhout)写了一份名为“开放决策制定(Open Decision Making)”的好文档，内容虽然来自他在创业公司的经验，但它几乎完全适用于开源项目。 在这份文档中，他提出的最重要的观点之一是：如果一群聪明人面对同一个问题，并具有相同的信息，如果他们有相同的目标，那么他们很可能得出相同的结论。 如果你和我在Go中是否要嵌入Perl这个问题上存在分歧，根本原因肯定是我们对Go目标有不同的理解，所以我们必须建立明确Go的目标。 Go的目标是更好的软件工程，特别是大规模软件工程。Go的独特设计决策几乎全部针对这个目标。我们已经多次阐述过这一点，包括在上述截图中的这两篇文章中。再说一次，Go的目标是更好的软件工程。 现在我们来说说Perl。20年前，当我很年轻、甚至有些天真、Go还不存在的时候，我编写并部署了一个完全用Perl编写的大型分布式系统。我热爱Perl所擅长的东西，但它并不是以更好的软件工程为目标。如果我们在这一点上有分歧，那么我可能应该定义一下我所说的软件工程是什么意思。 注：如果要理解Go以更好软件工程为目标，或是Google的软件工程理念，可以阅读一下《Software Engineering at Google》这本佳作。 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/go-changes-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2023/12/10/go-changes">本文永久链接</a> &#8211; https://tonybai.com/2023/12/10/go-changes</p>
<p>自从Go语言之父Rob Pike从Google退休并隐居澳洲后，Russ Cox便成为了Go语言团队的“带头大哥”，虽然其资历还无法与依旧奋战在一线的另外一位Go语言之父Robert Griesemer相比。如今，Russ Cox对Go语言未来的演化发展是很有“发言权”的，Go module的引入便是Russ Cox的重要决策之一。从Go社区来看，这些年来，以Russ Cox为首的Go团队对Go演进决策总体上是良性的、受欢迎的，比如Go module、Go泛型、Go对wasm的支持等，当然也有一些变化是受到质疑的，比如：<a href="https://github.com/golang/go/issues/60078">Go 1.22版本很可能从试验特性到正式特性的loopvar等</a>。</p>
<blockquote>
<p>注：我的极客时间<a href="http://gk.link/a/10AVZ">《Go语言第一课》</a>专栏中有对Go module和Go泛型的详细讲解，欢迎感兴趣的童鞋订阅阅读。</p>
</blockquote>
<p>想必很多Gopher也和我一样，对Go团队就某一proposal的决策方式和依据很好奇 &#8211;到底他们是如何决定是否accept这个proposal的？Go语言后续该如何演化？向哪个方向发展演化？</p>
<p>今年9月份举办的GopherCon 2023上，Russ Cox代表Go团队做了名为<a href="https://www.youtube.com/watch?v=BNmxtp26I5s">“Go Changes”的主题演讲</a>：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-2.png" alt="" /></p>
<p>在这个talk中，我们能找到一些答案。近期他<a href="https://research.swtch.com/gochanges">重新录制了该演讲视频</a>，并在其个人博客中放出。</p>
<p>本文就是基于这个视频内容进行整理加工后的文字稿，供国内广大gopher参考。</p>
<hr />
<p>这是我在2023年GopherCon上做的一次演讲的重新录制视频。在这次演讲中，我和大家分享了三部分内容：为什么Go需要随着时间的推移而改变，我们如何应对Go的变化过程，以及为什么<a href="https://research.swtch.com/telemetry-intro">选择性遥测(opt-in telemetry)</a>是这个过程中的一个重要且适当的部分。不过，这个演讲不是关于某个特定的Go特性变化，而是关于Go整体的变化过程，特别是我们是如何决定做出哪些改变的。</p>
<p>首先一个明显的问题是，为什么Go需要改变? <strong>为什么我们不能对Go感到满意，然后将其束之高阁呢</strong>? 一个显而易见的答案是<strong>我们不可能一次就把事情做对</strong>，你对比一下上面图片中展示的第一版毛绒Go吉祥物和我们在GopherCon上发放的最终版本，你就能明白我的意思了。</p>
<p>但这里还有一个更深层次的答案：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-3.png" alt="" /></p>
<p>我的一位前同事在他使用了多年的邮件签名中引用了生物学家兼科幻小说作家杰克·科恩(Jack Cohen)的一句名言。在这句名言中，科恩说：“我们生物学家使用的一个描述‘稳定(stable)’的专业词汇就是“死(dead)”。</p>
<p>所有的生命都在变化，适应新的环境，修复损伤等。<a href="https://tonybai.com/2022/05/04/the-paper-of-go-programming-language-and-environment">编程环境</a>也需要改变。除非我们想要Go死掉，否则它需要适应新的环境，比如新的协议、操作系统和重要用例。我们也需要发现并修复bug &#8212; 语言、库和生态系统的问题，这些问题只有随着时间的推移或Go发展到一定阶段和规模才会暴露出来。</p>
<p><strong>Go必须改变，并与时俱进</strong>。这次演讲就是<strong>关于我们如何决定做出哪些改变</strong>。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-4.png" alt="" /></p>
<p>这次演讲分三个部分:</p>
<ul>
<li>第一部分是关于我们对Go的愿景和期望。</li>
<li>第二部分是关于我们如何利用数据来决定做出哪些改变。</li>
<li>第三部分是关于我们在<a href="https://tonybai.com/2023/09/10/understand-go-forward-compatibility-and-toolchain-rule/">Go工具链</a>中增加选择性遥测的计划，以便更好地理解Go的使用情况和出现问题的地方。</li>
</ul>
<p>到演讲结束时，你将了解我们考量和决定Go变化的过程，并了解数据在做出这些决定中的重要性，我希望你能理解为什么选择性遥测是一个很好的额外数据来源，甚至可能愿意在系统推出时就选择加入。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-5.png" alt="" /></p>
<p>让我们从这个开始：我们希望Go发生什么样的变化？如果我们在这个基本问题上意见不一致，我们也就无法就具体的变化达成共识。</p>
<p>例如，我们是否应该在Go中添加一个Perl语句，让我们可以用Perl编写函数?</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-6.png" alt="" /></p>
<p>我认为我们不应该，但假设你有不同意见。为了解决这个问题，我们需要理解为什么我们持不同意见。</p>
<p>约翰·奥斯特豪特(John Ousterhout)写了一份名为“<a href="https://www.web.stanford.edu/~ouster/cgi-bin/decisions.php">开放决策制定(Open Decision Making)</a>”的好文档，内容虽然来自他在创业公司的经验，但它几乎完全适用于开源项目。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-7.png" alt="" /></p>
<p>在这份文档中，他提出的最重要的观点之一是：<strong>如果一群聪明人面对同一个问题，并具有相同的信息，如果他们有相同的目标，那么他们很可能得出相同的结论</strong>。</p>
<p>如果你和我在Go中是否要嵌入Perl这个问题上存在分歧，根本原因肯定是<strong>我们对Go目标有不同的理解</strong>，所以我们必须建立明确Go的目标。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-8.png" alt="" /></p>
<p>Go的目标是更好的软件工程，特别是大规模软件工程。<a href="https://go.dev/talks/2012/splash.article">Go的独特设计决策几乎全部针对这个目标</a>。我们已经多次阐述过这一点，包括在上述截图中的<a href="https://tonybai.com/2022/05/04/the-paper-of-go-programming-language-and-environment">这两篇文章中</a>。再说一次，<strong>Go的目标是更好的软件工程</strong>。</p>
<p>现在我们来说说Perl。20年前，当我很年轻、甚至有些天真、Go还不存在的时候，我编写并部署了一个完全用Perl编写的大型分布式系统。我热爱Perl所擅长的东西，但它并不是以更好的软件工程为目标。如果我们在这一点上有分歧，那么我可能应该定义一下我所说的软件工程是什么意思。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-9.png" alt="" /></p>
<blockquote>
<p>注：如果要理解Go以更好软件工程为目标，或是Google的软件工程理念，可以阅读一下《<a href="https://book.douban.com/subject/34875994/">Software Engineering at Google</a>》这本佳作。</p>
</blockquote>
<p>我喜欢说，当你给编程加入时间和其他程序员时，软件工程就出现了。编程意味着让一个程序工作。你有一个要解决的问题，你编写一些代码，运行它，调试它，得到答案，完成。这就是编程，这已经够难的了。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-10.png" alt="" /></p>
<p>但是当那段代码不得不日复一日地继续工作时会发生什么，甚至和其他人一起对它进行维护？那么你需要添加测试，以确保你修正后的bug不会在6个月后由你自己或是一个不熟悉这段代码的新团队成员重新引入。这就是为什么Go从第一天开始就内置了对测试的支持，并建立了一种文化，那就是对任何bug的修复或新增代码都要添加测试。</p>
<p>那么随着时间的流逝，当代码必须在Go本身发生改变的情况下继续工作时会发生什么？那么我们需要强调<a href="https://go.dev/doc/go1compat">兼容性</a>，这是Go1版本以来一直在做的。事实上，<a href="https://tonybai.com/2023/08/20/some-changes-in-go-1-21/">Go 1.21版本</a>发布了<a href="https://tonybai.com/2023/09/10/understand-go-forward-compatibility-and-toolchain-rule/">许多兼容性改进</a>，我在2022年的GopherCon上对此有过介绍。</p>
<p>随着代码量的增长，如果需要某种全局清理时该怎么办？你需要工具，而不可避免的第一个绊脚石是那些工具需要模仿代码的格式化风格来编辑，以避免出现无关的差异。gofmt的存在是为了支持goimports、gorename、go fix和gopls等工具，以及你自己可能使用我们提供的包编写的自定义工具。</p>
<p>既然提到了软件包，当你使用其他人提供的软件包时，不可避免的第一个绊脚石是多个人会用相同的名字(比如sqlite或yaml)编写软件包。那么我们如何在一个给定的程序中识别究竟使用哪个了呢？为了在一个去中心化的方式无歧义地回答这个问题，Go使用URL作为包导入路径。</p>
<p>随着时间的推移，下一个问题是挑选使用特定软件包的哪个版本，并决定该版本是否与所有其他依赖项兼容。这就是为什么Go提供了modules、<a href="https://tonybai.com/2021/11/12/go-workspace-mode-in-go-1-18">workspaces</a>、Go modules mirror镜像和Go module校验和数据库。</p>
<p>接下来的问题是每个人的代码都有bug，包括安全bug。你需要了解关于最重要bug的信息，这样你就知道需要更新到已修复的版本。这就是为什么我们添加了Go漏洞数据库和<a href="https://tonybai.com/2022/09/10/an-intro-of-govulncheck">govulncheck</a>，Julie也在GopherCon上谈到了这一点，当有视频链接时我会在下面添加。</p>
<p>以上是较大的例子，但也有小的例子，比如添加新的协议如HTTP/3，移除对过时平台的支持，以及修复或废弃容易出错的API，以避免大型代码库中的常见错误。</p>
<p>这把我们带到了Go提案过程(Proposal Process)，这是我们对是否接受(accept)和拒绝(decline)哪些变更做出决定的方式：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-11.png" alt="" /></p>
<p>当我们考虑这些决定时，使用数据非常重要，这可以帮助我们达成共识。</p>
<p>简单地说，任何人都可以在Go的GitHub问题跟踪器上提出Go更改提案(Change Proposal)。然后，在该问题上进行讨论，我们试图在参与者之间就是否接受或拒绝该建议达成共识，或者该建议需要做出什么修改才能被接受。</p>
<p>随着时间的推移，我们越来越欣赏约翰·奥斯特豪特在他的观察中提出的第二句话的重要性：如果面对问题的人不仅共同的目标，<strong>还有共同的信息</strong>，他们很可能会达成共识。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-12.png" alt="" /></p>
<p>在Go的早期，只有我们几个人做决定。我们根据技术判断和直觉做出决定，这些判断和直觉是基于我们过去的经验。那些经验就是我们使用的信息。由于我们的过去经验有足够的重叠，我们大多数时候能达成共识。大多数小项目都是这种工作方式。</p>
<p>随着决策涉及的人数大大增加，共享经验就会减少。我们需要一个新的共享信息来源。我们发现的最好信息来源是收集实际数据，然后将这些数据作为共享信息来做决策。但是我们从哪里获得这些数据呢？对Go来说，我们有许多潜在的来源，每一个都适合具体的决策类型。在这里，我将向你展示其中的一些。</p>
<p>一个数据来源是<strong>与Go用户交谈</strong>。我们以各种方式做到这一点：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-13.png" alt="" /></p>
<p>首先是Go用户调查，我们从2016年开始每年做一次，最近开始一年做两次。调查非常适合了解Go最流行的用途以及人们面临的最常见问题。多年来，最常见的问题是<strong>缺乏依赖管理和泛型</strong>。我们使用这些信息将开发Go模块和泛型作为优先事项。</p>
<p>另一个数据来源是我们可以在VSCode中使用VSCode Go插件运行的调查。这些调查可以帮助我们了解VSCode Go体验的实效性。</p>
<p>来自用户的最后一个直接数据来源是我们全年进行的研究访谈和用户体验研究。这些研究允许我们从小规模的用户群体中识别模式或获取更多关于特定主题的信息。</p>
<p>调查和访谈通过与用户交谈来收集数据。另一个数据来源是<strong>阅读代码</strong>：我们可以分析已发布的开源Go module代码。</p>
<p>例如，在添加新的“go vet”检查之前，我们会在开源代码库的一个子集上运行它，然后读取一些随机样本的结果，看检查是否指出了真实的问题，以及它是否有太多的假阳性。</p>
<p>在Go 1.22版本，我们计划添加一个go vet检查，检查对append的调用是否没有append任何内容。这里有检查器标记的两段代码：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-14.png" alt="" /></p>
<p>顶部的一段代码表明开发人员可能认为append总是复制其输入slice。底部的一段代码可能是正确的，但难于措辞来描述。</p>
<p>这里还有另外两段代码：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-15.png" alt="" /></p>
<p>在顶部的一段中，或者for循环从未运行，或者它永远不会完成，因为e.Sigs的长度永远不会改变。底部的代码也似乎是一个清晰的bug：代码正在仔细决定将消息追加到哪个列表中，然后它没有将其追加到任何一个列表中。</p>
<p>由于我们对样本代码段进行的所有采样都是可疑的或完全错误的，我们决定添加该检查。在这里，数据比直觉更好。</p>
<p>所有这些方法都是在少量样本上工作。对于典型的代码分析，我喜欢手动检查100个样本，与世界上所有Go代码的量相比，这只是一个微小的比例。最后一份Go开发者调查有不到6000名受访者，而全世界可能有300万Go开发者，样本比例不到1%。</p>
<p>一个很好的问题是为什么这些极小的样本能告诉我们有关更大人群的信息？答案是抽样精度只依赖于样本数量，而不依赖于总体规模。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-16.png" alt="" /></p>
<p>这乍一看似乎反直觉，但假设我有一个装有100万只Go吉祥物的大箱子，我随机拿出两个。首先我拿到一个蓝色的，然后我拿到一个粉红色的。根据这两个样本，我估计箱子中的吉祥物大约一半是蓝色的，一半是粉红色的。但如果我告诉你箱子里有粉红色、蓝色和灰色的吉祥物，你是否会感到十分惊讶? 不会非常惊讶！如果箱子正好分三分之一粉红色、蓝色和灰色，那么这9对颜色组合中的每一对都同样可能：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-17.png" alt="" /></p>
<p>得到一个非灰色吉祥物的机会是2/3，得到两个的机会就是2/3的平方，即4/9。没看到灰色的情况出现概率将近一半。这就是为什么我们不会非常惊讶的原因。</p>
<p>现在假设我取出100只，有48只蓝色和52只粉红色。我再次估计箱子大约一半是蓝色，一半是粉红色。现在如果我告诉你箱子里有粉红色、蓝色和灰色的吉祥物，你会有多惊讶？你应该会非常惊讶。</p>
<p>事实上，你完全不应该相信我。如果那是真的，得到100只连续的非灰色吉祥物的机会是2/3的100次方，约等于10的负48次方：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-18.png" alt="" /></p>
<p>随机出现这种情况的可能性为零。要么我在说谎，要么我没有随机抽取。可能所有的灰色吉祥物都在箱子底部，我没有抽取到足够深的地方。</p>
<p>请注意：<strong>这都不依赖于箱子中有多少只Go吉祥物，它只取决于我们取出了多少只</strong>。用于特定预测精度的数学更复杂，但具有相同的效果：<strong>只有样本数量重要，箱子中的吉祥物数目不重要</strong>。</p>
<p>一般来说，手工计算这些数学太困难了，所以这里有一个表格，你可以在我的博客上找到：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-19.png" alt="" /></p>
<p>它说明，如果你提取100个样本并根据这些样本估计百分比，那么90%的时间你的估计将在真实百分比的正负8%之内。99%的时间它们将在13%之内。如果像Go调查中那样有5000个样本，那么90%的时间估计误差在正负1%之内，99%的时间在正负2%之内。超过这个数量，我们实际上不需要更多样本。</p>
<p>有一个注意事项是样本需要是随机的, 或者至少与你正在估计的内容不相关。你不能只从箱子的顶部抽取吉祥物，然后对整个箱子做出断言。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-20.png" alt="" /></p>
<p>如果你避免了这个错误, 那么当你试图估计一个新的API是否有用或者某个特定的vet check是否值得的时候, 花一个小时左右手动检查100个样本是合理的。如果是一个坏主意, 那将很快显现出来。而如果看起来是一个好主意, 再花几个小时检查更多的样本, 无论是手动检查还是用程序检查，都会大大提高你的估计准确性。与做出错误决策的代价相比，这是一个非常小的成本。</p>
<p>简而言之，采样的魔力在于将许多一次性估计转变为可以手动或用少量数据完成的工作。这就是为什么我们已经看到的所有数据来源都能够相当好地代表整个Go开发者群体的原因。</p>
<p>现在进入演讲的第三部分：Go工具链中的遥测(Telemetry)：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-21.png" alt="" /></p>
<p>遥测也将是Go开发者使用的一个小样本，但它应该是一个有代表性的样本，并且回答不同的问题，而不是调查和代码分析所做的问题。</p>
<p>遥测始终是一个有争议的话题，特别是对于开源项目来说，所以让我从最重要的细节开始说起：上传遥测报告是完全自愿和选择加入的：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-22.png" alt="" /></p>
<p>除非你运行一个显式命令选择加入数据收集，否则不会上传任何数据。而且，这不是那种上传你的全部活动的详细跟踪的遥测系统。这种遥测也只适用于我们作为Go发行版的一部分分发的命令，比如gopls、go命令和编译器(compiler)，<strong>它不会涉及你构建的任何程序</strong>。</p>
<p>在我更详细地描述完这个系统之后，我希望你会发现你会愿意选择加入这个遥测系统。实际上，我们给自己设定的主要设计限制是，即使由其他人运行，我们也愿意选择加入该系统。</p>
<p>在我以2023年11月的录制这个内容时，该系统刚刚开始运行，只有少数人被要求在VSCode Go中选择加入gopls遥测。所以总体来说，你现在还不能选择加入。但希望很快你就可以了。</p>
<p>在我们深入了解细节之前，遥测的动机是它提供了与调查和代码分析不同的信息。它主要提供的两个类别是使用信息(Usage Information)和故障信息(Breakage Information)。调查让我们能够询问关于Go使用的广泛问题，但对于详细的使用信息来说并不好。那将是太多问题，对于调查对象来说，90%的问题要回答”no”是一种浪费时间。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-23.png" alt="" /></p>
<p>这个幻灯片显示了我们在之前的版本中警告过即将删除的Go功能列表。列表中的最后一项，buildmode=shared，是我们试图移除的功能，但在事先警告后，至少有一个用户提出了异议，我们将其保留了下来。即便如此，buildmode=shared与Go module基本不兼容，所以它的使用可能非常有限。但我们没有数据，所以它仍然存在于代码库中。遥测可以为我们提供基本的使用信息，以便我们可以基于数据而不是猜测做出这些决策。</p>
<p>另一个重要的类别是故障信息：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-24.png" alt="" /></p>
<p>如果Go工具链明显有问题，我们希望在GitHub上收到错误报告。但是Go工具链也可能以用户注意不到的微妙方式出现问题。一个例子是，在macOS上的Go 1.14到Go 1.19的版本中，标准库包的二进制文件在预先构建时使用了非默认的编译标志，这是一个意外，这使得它们看起来像是过时了，Go命令在运行时会重新编译它们，这意味着如果你的程序导入了net包，你需要安装Xcode中的C编译器来构建程序。我们希望Go能够自行构建纯Go程序，而无需其他工具链。因此，要求安装Xcode是一个bug。但是我们没有注意到这个问题，也没有用户在GitHub上报告它。遇到这个问题的人似乎只是安装了Xcode并继续进行了工作。遥测可以提供基本的性能指标，比如标准库缓存命中率，这样Go工具链的开发人员即使用户没有意识到这个问题，也能注意到这个问题。</p>
<p>另一个例子是编译器的内部崩溃：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-25.png" alt="" /></p>
<p>Go编译器在程序的第一个错误处不会停止。它会继续进行，尽可能多地查找和报告不同的错误。但是有时，继续分析已知错误的程序会导致意外的panic。我们不希望向用户显示这样的崩溃。相反，编译器会从panic中恢复，并且仅报告已经发现的错误。这样，Go用户可以纠正这些错误，这也可能纠正隐藏的panic。用户的工作不会因为看到编译器崩溃而中断。这对用户来说是好的，但是Go工具链的开发人员仍然希望了解这个崩溃并修复这个错误。遥测可以确保即使用户不知道这个错误，但我们还能了解到这个错误。</p>
<p>为了收集使用情况和故障信息，Go遥测设计记录“计数器和崩溃”：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-26.png" alt="" /></p>
<p>像go命令、Go编译器或gopls这样的Go工具链程序可以定义命名事件计数器，并在事件发生时递增计数器。事件还可以按堆栈跟踪单独计数。这些计数器在本地的磁盘文件中维护，每次保留一周的时间。在幻灯片上，gopls和其他工具正在将计数器写入每周的文件中。</p>
<p>每周一次，Go工具链中的上传程序(uploader)将从遥测服务器获取一个“上传配置”，其中列出了该周收集的特定事件名称。只有在遥测特定的提案审查过程达成共识后，才会更改该配置。该配置作为一个模块(module)提供，以保护下载的完整性，并保留过去配置的公共记录。然后，上传程序仅上传上传配置中列出的计数器。在幻灯片上，上传程序仅为gopls发送一份报告，仅包含少量计数器，即使磁盘上可能还有更多计数器。报告中包含关于使用gopls的编辑器的统计信息，以及关于完成请求的延迟的信息，还有一个发生了一次的gopls/bug事件，其中包含一个栈跟踪。</p>
<p>请注意，上传的数据中没有事件跟踪或任何用户数据，只有计数器、已在公共上传配置中列出的事件名称，以及Go工具链程序中的函数名称。还要注意，栈跟踪不包括任何函数的参数，只有函数名称，因此没有用户数据。</p>
<p>开源中的遥测可能会在拥有数据访问权限和没有数据访问权限的人之间产生信息失衡。我们希望避免这种情况。请记住奥斯特豪特规则：为了达成共识，我们需要每个人拥有相同的信息。由于Go的遥测上传不包含任何敏感数据，并且是在明确的选择同意的情况下收集的，我们可以完整地重新发布这些报告，以便任何人都可以进行任何数据分析。我们还将发布一些基本的图表，用于做出决策。我们唯一可能看到但没有重新发布的是报告来自哪些IP地址，我们的服务器会将这些信息与报告一起记录。</p>
<p>一个明显的问题是，是否有足够多的人选择启用遥测，以使数据足够准确以做出决策。幸运的是，采样的神奇之处在于可以帮助解决这个问题。</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-27.png" alt="" /></p>
<p>全球大约有300w Go开发者。当系统准备就绪并要求人们启用遥测时，即使只有千分之一的开发者选择参与，也会有3000名开发者，根据我们的图表显示，误差不到3%，置信度为99%。如果全球三分之二的Go开发者启用了遥测，那将是20000个样本，误差不到1%，置信度为99%。除此之外，我们实际上不需要更多的样本。如果我们持续获得更多的报告，我们可以调整上传配置，告诉系统在某个特定的周选择随机不上传任何东西。例如，如果有20万个系统选择了参与，我们可以告诉每个系统在任何给定的周上传的概率为10%。因此，即使我们预计选择参与率会很低，系统应该能够运行得很好，随着选择参与率的提高，Go遥测将从任何给定系统收集更少的数据。当然，这使得每个选择参与的人对我们来说更加重要。目前来说，Go遥测对于你们中的任何人来说都还没有准备好，但当准备好时，我希望你们会选择参与。</p>
<p>在结束之前，我希望你们从演讲中获得以下几点：</p>
<p><img src="https://tonybai.com/wp-content/uploads/go-changes-28.png" alt="" /></p>
<p>首先，Go需要不断变化，特别是随着计算世界的变化。</p>
<p>其次，任何改变的目标都是为了使Go在软件工程中变得更好，尤其是在规模化(scaling)方面。</p>
<p>第三，一旦我们确定了目标，达成共识的下一个最重要的部分是拥有共享数据来做出决策。</p>
<p>第四，Go工具链遥测是增补我们现有调查和代码分析数据的重要数据来源。</p>
<p>最后，在整个演讲中，虽然涉及到了数据和适当的统计，但我们评估的想法、假设和潜在的变化始终始于个人故事和对话。我们喜欢听到这些故事，并与你们所有人讨论如何使用Go，关于什么有效和什么无效。所以，请无论在什么情况下，无论是在会议上、邮件列表上还是在问题跟踪器上，请确保让我们知道Go对你们的工作情况以及存在的问题。我们总是很乐意听到这些。非常感谢。</p>
<hr />
<p><a href="https://public.zsxq.com/groups/51284458844544">“Gopher部落”知识星球</a>旨在打造一个精品Go学习和进阶社群！高品质首发Go技术文章，“三天”首发阅读权，每年两期Go语言发展现状分析，每天提前1小时阅读到新鲜的Gopher日报，网课、技术专栏、图书内容前瞻，六小时内必答保证等满足你关于Go语言生态的所有需求！2023年，Gopher部落将进一步聚焦于如何编写雅、地道、可读、可测试的Go代码，关注代码质量并深入理解Go核心技术，并继续加强与星友的互动。欢迎大家加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-tribe-zsxq-small-card.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/go-programming-from-beginner-to-master-qr.png" alt="img{512x368}" /></p>
<p><img src="http://image.tonybai.com/img/tonybai/go-first-course-banner.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/imooc-go-column-pgo-with-qr.jpg" alt="img{512x368}" /></p>
<p>著名云主机服务厂商DigitalOcean发布最新的主机计划，入门级Droplet配置升级为：1 core CPU、1G内存、25G高速SSD，价格5$/月。有使用DigitalOcean需求的朋友，可以打开这个<a href="https://m.do.co/c/bff6eed92687">链接地址</a>：https://m.do.co/c/bff6eed92687 开启你的DO主机之路。</p>
<p>Gopher Daily(Gopher每日新闻) &#8211; https://gopherdaily.tonybai.com</p>
<p>我的联系方式：</p>
<ul>
<li>微博(暂不可用)：https://weibo.com/bigwhite20xx</li>
<li>微博2：https://weibo.com/u/6484441286</li>
<li>博客：tonybai.com</li>
<li>github: https://github.com/bigwhite</li>
<li>Gopher Daily归档 &#8211; https://github.com/bigwhite/gopherdaily</li>
</ul>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。</p>
<p style='text-align:left'>&copy; 2023, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2023/12/10/go-changes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Go 1.21中值得关注的几个变化</title>
		<link>https://tonybai.com/2023/08/20/some-changes-in-go-1-21/</link>
		<comments>https://tonybai.com/2023/08/20/some-changes-in-go-1-21/#comments</comments>
		<pubDate>Sun, 20 Aug 2023 14:31:22 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AfterFunc]]></category>
		<category><![CDATA[backward-compatibility]]></category>
		<category><![CDATA[builtin]]></category>
		<category><![CDATA[clear]]></category>
		<category><![CDATA[cmp]]></category>
		<category><![CDATA[constant]]></category>
		<category><![CDATA[constraints]]></category>
		<category><![CDATA[Context]]></category>
		<category><![CDATA[ErrUnsupported]]></category>
		<category><![CDATA[for]]></category>
		<category><![CDATA[forloop]]></category>
		<category><![CDATA[forward-compatibility]]></category>
		<category><![CDATA[GC]]></category>
		<category><![CDATA[generics]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[go1.19]]></category>
		<category><![CDATA[go1.20]]></category>
		<category><![CDATA[go1.21]]></category>
		<category><![CDATA[go1.22]]></category>
		<category><![CDATA[Go2]]></category>
		<category><![CDATA[GODEBUG]]></category>
		<category><![CDATA[GOEXPERIMENT]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[gopherchina]]></category>
		<category><![CDATA[GopherCon]]></category>
		<category><![CDATA[goroutine]]></category>
		<category><![CDATA[Go语言第一课]]></category>
		<category><![CDATA[Go语言精进之路]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[loop]]></category>
		<category><![CDATA[loopvar]]></category>
		<category><![CDATA[main]]></category>
		<category><![CDATA[maps]]></category>
		<category><![CDATA[max]]></category>
		<category><![CDATA[min]]></category>
		<category><![CDATA[Ordered]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[panic]]></category>
		<category><![CDATA[PGO]]></category>
		<category><![CDATA[QUIC]]></category>
		<category><![CDATA[RussCox]]></category>
		<category><![CDATA[slices]]></category>
		<category><![CDATA[slog]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[TinyGo]]></category>
		<category><![CDATA[toolchain]]></category>
		<category><![CDATA[wasi]]></category>
		<category><![CDATA[wasm]]></category>
		<category><![CDATA[wazero]]></category>
		<category><![CDATA[WebAssembly]]></category>
		<category><![CDATA[包]]></category>
		<category><![CDATA[包初始化]]></category>
		<category><![CDATA[变长参数]]></category>
		<category><![CDATA[向前兼容]]></category>
		<category><![CDATA[向后兼容]]></category>
		<category><![CDATA[垃圾回收]]></category>
		<category><![CDATA[多路径TCP]]></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=3968</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2023/08/20/some-changes-in-go-1-21 美国时间2023年8月8日，Go团队在Go官博上正式发布了1.21版本！ 早在今年4月末，我就撰写了文章《Go 1.21新特性前瞻》，对Go 1.21可能引入的新特性、新优化和新标准库包做了粗略梳理。 在6月初举办的GopherChina 2023大会上，我又以“The State Of Go 2023”为题目给大家分享了Go 1.21版本的当前状态： 那么以上分享的内容在Go 1.21的正式版中究竟真正落地了没有？Go 1.21正式版中还有哪些在之前的分享资料中未曾介绍的值得注意的变化呢？在这篇系列文章中，我们就来看一看。 注：从Go 1.21版本开始，Go Release版本的起始版本号(first release of the release family)由Go 1.N改为Go 1.N.0了。Go语言版本号(language version)依旧是Go 1.N，同时Go Release Family的版本号也依然是Go 1.N。 1. 语言变化 和以往的系列文章一样，我们先来看看语言特性方面有哪些值得注意的变化。 众所周知，Go语法特性变化甚少，在一些新版本中没有语言特性变化反倒是一种常态。在去年GopherCon 2022大会上，Russ Cox发表“How Go Programs Keep Working”的主题演讲，演讲中Russ Cox就提到：“我们发布Go 1.0版本及兼容性承诺，就是为了停止那种兴奋，以便Go的新版本会变得boring(平淡无奇)”，并且Go team认为boring is good, boring is stable： 这也意味着在未来Go的演化过程中，Go依旧会保持极少增加语言特性的节奏。 注：不要认为一门编程语言要保持boring很容易，在这篇文章后面也会提到Go核心团队对如何保持boring(向前向后兼容性)的思考和手段。 Go 1.21版本中，Go语言特性的变化还是可以的，主要是增加了几个builtin预定义函数、明确了包初始化顺序的算法、增强了泛型的类型推断能力并以实验性选项的方式修正了Go1中的两个容易导致问题的语法语义。接下来，我们就来逐个具体说明一下。 我们先来看看builtin中预定义函数的变化。 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/some-changes-in-go-1-21-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2023/08/20/some-changes-in-go-1-21">本文永久链接</a> &#8211; https://tonybai.com/2023/08/20/some-changes-in-go-1-21</p>
<p>美国时间2023年8月8日，<a href="https://go.dev/doc/go1.21">Go团队在Go官博上正式发布了1.21版本</a>！</p>
<p>早在今年4月末，我就撰写了文章《<a href="https://tonybai.com/2023/04/26/go-1-21-foresight/">Go 1.21新特性前瞻</a>》，对Go 1.21可能引入的新特性、新优化和新标准库包做了粗略梳理。</p>
<p>在6月初举办的<a href="https://github.com/gopherchina/conference">GopherChina 2023大会上</a>，我又以<a href="https://mp.weixin.qq.com/s/-EAH8jjj4uy1LCr_9C1ghg">“The State Of Go 2023”</a>为题目给大家分享了Go 1.21版本的当前状态：</p>
<p><img src="https://tonybai.com/wp-content/uploads/some-changes-in-go-1-21-2.png" alt="" /></p>
<p>那么以上分享的内容在Go 1.21的正式版中究竟真正落地了没有？Go 1.21正式版中还有哪些在之前的分享资料中未曾介绍的值得注意的变化呢？在这篇系列文章中，我们就来看一看。</p>
<blockquote>
<p>注：从Go 1.21版本开始，Go Release版本的起始版本号(first release of the release family)由Go 1.N改为Go 1.N.0了。Go语言版本号(language version)依旧是Go 1.N，同时Go Release Family的版本号也依然是Go 1.N。</p>
</blockquote>
<h2>1. 语言变化</h2>
<p>和以往的<a href="https://tonybai.com/2023/02/08/some-changes-in-go-1-20/">系列文章</a>一样，我们先来看看语言特性方面有哪些值得注意的变化。</p>
<p>众所周知，Go语法特性变化甚少，在一些新版本中<strong>没有语言特性变化反倒是一种常态</strong>。在去年<a href="https://www.gophercon.com">GopherCon 2022大会</a>上，Russ Cox发表<a href="https://www.youtube.com/watch?v=v24wrd3RwGo">“How Go Programs Keep Working”的主题演讲</a>，演讲中Russ Cox就提到：“我们发布Go 1.0版本及兼容性承诺，就是为了停止那种兴奋，以便Go的新版本会变得boring(平淡无奇)”，并且Go team认为boring is good, boring is stable：</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2022-review-of-go-programming-language-3.png" alt="" /></p>
<p>这也意味着在未来Go的演化过程中，Go依旧会保持极少增加语言特性的节奏。</p>
<blockquote>
<p>注：不要认为一门编程语言要保持boring很容易，在这篇文章后面也会提到Go核心团队对如何保持boring(向前向后兼容性)的思考和手段。</p>
</blockquote>
<p>Go 1.21版本中，Go语言特性的变化还是可以的，主要是增加了几个builtin预定义函数、明确了包初始化顺序的算法、增强了泛型的类型推断能力并以实验性选项的方式修正了Go1中的两个容易导致问题的语法语义。接下来，我们就来逐个具体说明一下。</p>
<p>我们先来看看builtin中预定义函数的变化。</p>
<h3>1.1 min、max和clear</h3>
<p><a href="https://pkg.go.dev/builtin">builtin包</a>是变更“常客”，最近几个Go版本中，builtin包都有新变化。</p>
<blockquote>
<p>注：builtin包是一个特殊包，里面放置了Go语言预定义的标识符，用户层代码无需也不能导入builtin包。</p>
</blockquote>
<p>在Go 1.21版本中，builtin增加了三个预定义函数：min、max和clear。</p>
<p>顾名思义，min和max函数分别返回参数列表中的最小值和最大值，它们都是泛型函数，原型如下：</p>
<pre><code>func min[T cmp.Ordered](x T, y ...T) T
func max[T cmp.Ordered](x T, y ...T) T
</code></pre>
<p>通过原型我们看到，使用这两个函数时，参数的类型要相同，且至少要传入一个参数：</p>
<pre><code>// lang/min_max.go

var x, y int = 5, 6
fmt.Println(max(x))                    // 5
fmt.Println(max(x, y, 0))              // 6
fmt.Println(max("aby", "tony", "tom")) // tony
</code></pre>
<p>如果传入的参数的类型不同呢？我们看下面代码：</p>
<pre><code>// lang/min_max.go

var f float64 = 5.6
fmt.Printf("%T\n", max(x, y, f))    // invalid argument: mismatched types int (previous argument) and float64 (type of f)
fmt.Printf("%T\n", max(x, y, 10.1)) // (untyped float constant) truncated to int
</code></pre>
<p>我们看到：Go 1.21编译器报错，即便是untyped constant，如果类型不同，也会提醒你可能存在值精度的truncated。</p>
<p>max和min支持哪些类型呢？通过min和max原型中的类型参数(type parameter)可以看到，其约束类型(constraint)为cmp.Ordered，我们看一下该约束类型的定义：</p>
<pre><code>type Ordered interface {
    ~int | ~int8 | ~int16 | ~int32 | ~int64 |
        ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
        ~float32 | ~float64 |
        ~string
}
</code></pre>
<p>符合Ordered约束的上述这些类型以及衍生类型都可以使用min、max获取最小值和最大值。</p>
<p>相对于min、max两个函数的简单，新增的clear函数的语义就略复杂一些。在<a href="https://tonybai.com/2023/04/26/go-1-21-foresight">《Go 1.21新特性前瞻》</a>一文中提到过，这里再赘述一下:)</p>
<p>clear函数的原型如下：</p>
<pre><code>func clear[T ~[]Type | ~map[Type]Type1](t T)
</code></pre>
<p>从原型来看，clear的操作对象是切片和map类型，不过其执行语义因依操作的对象类型而异。我们看下面例子：</p>
<pre><code>// lang/clear.go

var sl = []int{1, 2, 3, 4, 5, 6}
fmt.Printf("before clear, sl=%v, len(sl)=%d, cap(sl)=%d\n", sl, len(sl), cap(sl))
clear(sl)
fmt.Printf("after clear, sl=%v, len(sl)=%d, cap(sl)=%d\n", sl, len(sl), cap(sl))

var m = map[string]int{
    "tony": 13,
    "tom":  14,
    "amy":  15,
}
fmt.Printf("before clear, m=%v, len(m)=%d\n", m, len(m))
clear(m)
fmt.Printf("after clear, m=%v, len(m)=%d\n", m, len(m))
</code></pre>
<p>这段代码的输出结果如下：</p>
<pre><code>before clear, sl=[1 2 3 4 5 6], len(sl)=6, cap(sl)=6
after clear, sl=[0 0 0 0 0 0], len(sl)=6, cap(sl)=6
before clear, m=map[amy:15 tom:14 tony:13], len(m)=3
after clear, m=map[], len(m)=0
</code></pre>
<p>我们看到：</p>
<ul>
<li>针对slice，clear保持slice的长度和容量，但将所有slice内已存在的元素(len个)都置为元素类型的零值；</li>
<li>针对map，clear则是清空所有map的键值对，clear后，我们将得到一个empty map。</li>
</ul>
<p>下面的表格是一个更直观、更泛化的clear函数语义总结：</p>
<p><img src="https://tonybai.com/wp-content/uploads/some-changes-in-go-1-21-3.png" alt="" /></p>
<blockquote>
<p>注：clear函数在清空map中的键值对时，并未释放掉这些键值所占用的内存。</p>
</blockquote>
<h3>1.2 明确了包初始化顺序算法</h3>
<p>在Go中，<a href="https://tonybai.com/2023/06/18/go-package-design-guide/">包既是功能单元，也是构建单元</a>，Go代码通过导入其他包来复用导入包的导出功能(包括导出的变量、常量、函数、类型以及方法等)。Go程序启动时，程序会首先将依赖的包按一定顺序进行初始化，但长久以来，Go语言规范并没有明确依赖包初始化的顺序，这可能会导致一些对包初始化顺序有依赖的Go程序在不同Go版本下出现行为的差异。</p>
<p>为了消除这些可能存在的问题，Go核心团队在Go 1.21中明确了包初始化顺序的算法。</p>
<blockquote>
<p>注：对包的初始化顺序有依赖，这本身就不是一种很好的设计，大家日常编码时应该注意避免。如果你的程序对包的初始化顺序存在依赖，那么升级到Go 1.21时你的程序行为可能会受到影响。</p>
</blockquote>
<p>这个算法比较简单，其步骤如下：</p>
<ul>
<li>将所有依赖包按照导入路径排序，放入一个list；</li>
<li>从list中按顺序找出第一个自身尚未初始化，但其依赖包已经全部初始化了的包，然后初始化该包，并将该包从list中删除；</li>
<li>重新执行上面步骤，直到list为空。</li>
</ul>
<p>再简单的算法，用文字描述都会很抽象晦涩，我们用一个例子来诠释一下。我们建立一个init_order的目录，里面的包之间的依赖关系如下图：</p>
<p><img src="https://tonybai.com/wp-content/uploads/some-changes-in-go-1-21-4.png" alt="" /></p>
<p>我们在init_order目录下按上面关系建立对应的包：</p>
<pre><code>$tree init_order
init_order
├── a
│   └── a.go
├── c
│   └── c.go
├── d
│   └── d.go
├── e
│   └── e.go
├── f
│   └── f.go
├── go.mod
├── main.go
└── z
    └── z.go

</code></pre>
<p>我们使用Go 1.21.0运行一下其中的main.go，得到如下结果：</p>
<pre><code>$go run main.go
init c
init d
init e
init f
init z
init a
</code></pre>
<p>这个结果是怎么来的呢？我们根据Go 1.21.0明确后的算法来分析一下，具体分析过程见下图：</p>
<p><img src="https://tonybai.com/wp-content/uploads/some-changes-in-go-1-21-5.png" alt="" /></p>
<p>将右侧每一轮选出的包按先后顺序排列一下，就是main.go的依赖包的初始化顺序：c d e f z a。</p>
<p>我们再用<a href="https://tonybai.com/2023/02/08/some-changes-in-go-1-20/">Go 1.20版本</a>运行一下这个示例，得到下面结果：</p>
<pre><code>init e
init f
init z
init a
init c
init d
</code></pre>
<p>我们看到这个顺序与Go 1.21版本的完全不同。</p>
<blockquote>
<p>注：我的<a href="http://gk.link/a/10AVZ">极客时间专栏《Go语言第一课》</a>的第8讲有对Go入口函数与包初始化次序的更为系统的讲解。</p>
</blockquote>
<h3>1.3 type inference的增强</h3>
<p>Go 1.21版本对泛型的类型推断能力做了增强。但<a href="https://go.dev/doc/go1.21">Go 1.21 Release Notes</a>以及<a href="https://go.dev/ref/spec#Type_inference">Go spec</a>中对这块的说明都十分晦涩，这里尝试用例子简要直观的说明一下。</p>
<p>此次的类型推断增强主要包含以下三个方面：</p>
<ul>
<li>部分实例化的泛型函数(Partially instantiated generic functions)</li>
</ul>
<p>我们以下面IndexFunc函数为例，来说明一下这方面的增强：</p>
<pre><code>// lang/type_inference/partially_instantiated_generic_func.go

// 该IndexFunc的实现来自Go 1.21的slices包
func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
    for i := range s {
        if f(s[i]) {
            return i
        }
    }
    return -1
}
</code></pre>
<p>我们使用上面IndexFunc函数返回一个整型切片中的第一个负数，我们可以这样做：</p>
<pre><code>func negative(n int) bool {
    return n &lt; 0
}

func main() {
    numbers := []int{0, 42, -10, 8}
    i := IndexFunc(numbers, negative)
    fmt.Println("First negative at index", i) // First negative at index 2
}
</code></pre>
<p>IndexFunc是一个泛型函数，它可以操作任意类型切片，于是你可能会想是否可以写一个泛型版的negative函数，这样就可以应对所有数值类型的切片了，比如：</p>
<pre><code>type Ordered interface {
    ~int | ~int8 | ~int16 | ~int32 | ~int64 |
        ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
        ~float32 | ~float64 |
        ~string
}

func negative[T Ordered](n T) bool {
    var zero T
    return n &lt; zero
}
</code></pre>
<p>接下来我们用这个泛型版negative函数作为IndexFunc的参数：</p>
<pre><code>func main() {
    numbers := []int{0, 42, -10, 8}
    i := IndexFunc(numbers, negative)
    fmt.Println("First negative at index", i)
}
</code></pre>
<p>用Go 1.21版本之前的Go编译器运行上述代码，我们会得到如下错误：</p>
<pre><code>./partially_instantiated_generic_func.go:32:26: cannot use generic function negative without instantiation
</code></pre>
<p>也就是说Go 1.21版本之前的Go编译器无法根据对IndexFunc的第二个参数的赋值来推断出参数f的类型实参。要想通过编译器检查，需显式传入类型实参，比如：negative[int]。</p>
<p>Go 1.21版本对此做了增强，支持在将negative赋值给IndexFunc的第二个参数时，根据IndexFunc的上下文环境(比如：第一个参数中的元素类型)推断出negative的类型实参。</p>
<p>这种部分实例化的泛型函数的典型应用就是在操作容器类类型的函数中。</p>
<ul>
<li>接口赋值推断(Interface assignment inference)</li>
</ul>
<p>为了解释什么是接口赋值推断，我们也来看一个例子(不要计较例子设计的合理性)：</p>
<pre><code>// lang/type_inference/interface_assignment_inference.go

type Indexable[T any] interface {
    At(i int) (T, bool)
}

func Index[T any](elems Indexable[T], i int) (T, bool) {
    return elems.At(i)
}

type MyList[T any] []T

func (m MyList[T]) At(i int) (T, bool) {
    var zero T
    if i &gt; len(m) {
        return zero, false
    }
    return m[i], true
}

func main() {
    var m = MyList[int]{11, 12, 13}
    fmt.Println(Index(m, 2))
}
</code></pre>
<p>我们使用Go 1.20版本运行这个示例，将得到下面错误结果：</p>
<pre><code>$go run interface_assignment_inference.go
./interface_assignment_inference.go:29:24: type MyList[int] of m does not match Indexable[T] (cannot infer T)
</code></pre>
<p>我们看到Go 1.20版本无法推断出泛型接口类型Indexable的类型实参。</p>
<p>但使用Go 1.21版本编译和运行，程序可以成功输出下面结果：</p>
<pre><code>$go run interface_assignment_inference.go
13 true
</code></pre>
<p>在Go 1.21中，类型推断也会考虑接口类型的方法。当一个值被赋值给一个接口时，编译器可以从匹配方法的相应参数类型中推断出接口类型的类型实参。</p>
<ul>
<li>对无类型常量的类型推断(Type inference for untyped constants)</li>
</ul>
<p>我们还是通过一个例子来理解一下：</p>
<pre><code>// lang/type_inference/untyped_constants_inference.go

func Sum[T int | float64](a ...T) T {
    var sum T
    for _, v := range a {
        sum += v
    }
    return sum
}

func main() {
    fmt.Printf("%T\n", Sum(1, 2, 3.5))
}
</code></pre>
<p>示例中的泛型函数Sum支持的类型实参为float64或int，但main函数调用Sum时使用了无类型常量，如果用Go 1.20版本编译器运行这段程序，我们将得到如下结果：</p>
<pre><code>$go run untyped_constants_inference.go
./untyped_constants_inference.go:14:31: default type float64 of 3.5 does not match inferred type int for T
</code></pre>
<p>Go 1.20在做类型实参推断时，仅考虑了单个传入的实参，这导致编译器认为3.5这个float64与推断出的int不匹配。</p>
<p>Go 1.21版本改善了这个推断算法：如果多个不同类型的无类型常量参数（如例子中的一个无类型的 int 和一个无类型的浮点常量）被传递给具有相同类型参数类型的参数，现在类型推断将使用与具有无类型常量操作数的运算符相同的方法来确定类型，而不是报错。这一改进使从无类型常量参数推断出的类型与常量表达式的求值后的类型一致。</p>
<p>这样，上面的Sum(1,2,3.5)推断出的类型实参的类型与1 + 2 + 3.5这个表达式的求值结果的类型一致，即float64！我们用Go 1.21版本运行一下上述示例程序：</p>
<pre><code>$go run untyped_constants_inference.go
float64
</code></pre>
<h3>1.4 修正Go1中的“陷阱”</h3>
<p>Go 1.21是一个“大”版本，这里的“大”并非是指Go 1.21涉及的内容广、变化多，而是指Go 1.21的一些变化的思路对后续版本可能有深远影响。比如Go 1.21就开启了修正Go1中一些语义“陷阱”的工作，并且这些修正可能会带来语义上的不向后兼容。不过<strong>这并不违反Go1兼容性承诺</strong>，因为在Go1兼容性承诺中，因对buggy语义或行为的修正而导致的对已有代码行为的破坏是允许的。</p>
<p>下面我们就来看看Go 1.21引入的两个“修正”。</p>
<h4>1.4.1 panic(nil)语义</h4>
<p>在Go 1.21中，Go编译器会将panic(nil)替换为panic(new(runtime.PanicNilError))，关于这个语义的变更，我在《<a href="https://tonybai.com/2023/04/26/go-1-21-foresight/">Go 1.21新特性前瞻</a>》一文中有详细说明，这里就不赘述了。</p>
<p>如果你要恢复原先的语义，可以使用GODEBUG=panicnil=1这个功能开关。</p>
<h4>1.4.2 loop var per-loop -> loop var per-iteration</h4>
<p>Go语言中的循环语句只有for这一种，for range是一种变体，专门用于对切片、数组、map和channel的遍历。</p>
<p>不过Go的for循环语句，尤其是for range语句有着很容易让程序出现错误的语义，即我们常说的“有坑”。</p>
<blockquote>
<p>注：我的<a href="https://item.jd.com/13694000.html">《Go语言精进之路vol1》</a>一书的第19条“了解Go语言控制语句惯用法及使用注意事项”中对for range的“坑”做了系统的梳理并给出了避坑建议。</p>
</blockquote>
<p>下面是一个典型的for range的“坑”的示例：</p>
<pre><code>// lang/loopvar/loopvar_per_loop.go

func main() {
    var m = [...]int{1, 2, 3, 4, 5}

    for i, v := range m {
        go func() {
            time.Sleep(time.Second * 3)
            fmt.Println(i, v)
        }()
    }

    time.Sleep(time.Second * 10)
}
</code></pre>
<p>这个示例意图在每次迭代启动的新的goroutine中输出迭代对应的i和v的值，但实际输出结果是什么呢？我们实际运行一下：</p>
<pre><code>$go run loopvar_per_loop.go
4 5
4 5
4 5
4 5
4 5
</code></pre>
<p>我们看到：goroutine中输出的i、v值都是for range循环结束后的i、v的最终值，而不是各个goroutine启动时的i、v值。这是因为goroutine执行的闭包函数引用了它的外层包裹函数中的变量i、v，这样变量i、v在主goroutine和新启动的goroutine之间实现了共享。</p>
<p>而i, v值在整个循环过程中是重用的，即仅有一份。在for range循环结束后，i = 4, v = 5，因此各个goroutine在等待3秒后进行输出的时候，输出的是i, v的最终值。</p>
<p>这里的i和v被称为loop var per loop，即<strong>一个循环语句定义一次的变量</strong>，等价于下面代码：</p>
<pre><code>{
    var i, v int
    for i, v = range m {
        //... ...
    }
}
</code></pre>
<p>一种解决这个问题的典型方法是这样的：</p>
<pre><code>// lang/loopvar/loopvar_per_iteration_classic.go
for i, v = range m {
    i := i
    v := v
    //... ...
}
</code></pre>
<p>我们在每个迭代中用短变量声明重新定义了在这次迭代中使用的i和v，这里的i和v就是<strong>loop var per-iteration</strong>的了。不过这个方法也存在问题，比如不能解决所有场景下的loop var per-iteration问题，另外就是需要手工创建。</p>
<p>Go团队决定在Go 1.22版本移除这个“坑”，并在Go 1.21版本中以实验语义(GOEXPERIMENT=loopvar)提供了默认采用loop var per-iteration语义的for循环(包括for range)。新语义仅在GOEXPERIMENT=loopvar且在for语句(包括for range)的前置条件表达式中使用短变量声明循环变量时才生效。</p>
<p>下面是for range的新语义的示例：</p>
<pre><code>// lang/loopvar/loopvar_per_iteration.go
package main

import (
    "fmt"
    "time"
)

func main() {
    var m = [...]int{1, 2, 3, 4, 5}

    for i, v := range m {
        go func() {
            time.Sleep(time.Second * 3)
            fmt.Println(i, v)
        }()
    }

    time.Sleep(time.Second * 10)
}
</code></pre>
<p>使用新语义运行该示例：</p>
<pre><code>$GOEXPERIMENT=loopvar go run loopvar_per_iteration.go
2 3
1 2
4 5
0 1
3 4
</code></pre>
<p>我们看到，新loopvar语义就相当于我们在每次迭代时手动重新定义i := i和v := v。</p>
<p>对于经典的3段式for循环语句，新loopvar语义的逻辑略复杂一些，我们用下面这个例子来理解一下：</p>
<pre><code>// lang/loopvar/classic_for_loop_in_1_21.go

func main() {
    var m = [...]int{1, 2, 3, 4, 5}

    for i := 0; i &lt; len(m); i++ {
        go func() {
            time.Sleep(time.Second * 3)
            fmt.Println(i, m[i])
        }()
    }

    time.Sleep(time.Second * 10)
}
</code></pre>
<p>采用经典的loopvar per loop语义执行上述代码：</p>
<pre><code>$go run classic_for_loop_in_1_21.go
panic: runtime error: index out of range [5] with length 5

goroutine 21 [running]:
main.main.func1()
    /Users/tonybai/Go/src/github.com/bigwhite/experiments/go1.21-examples/lang/loopvar/classic_for_loop_in_1_21.go:14 +0xb6
created by main.main in goroutine 1
    /Users/tonybai/Go/src/github.com/bigwhite/experiments/go1.21-examples/lang/loopvar/classic_for_loop_in_1_21.go:12 +0x76
exit status 2
</code></pre>
<p>由于各个goroutine通过闭包捕获到同一个i，而该i值在loop结束后为5，因此当以该i作为下标访问数组时，就会出现越界的panic。</p>
<p>我们再来在新loopvar语义下执行上面代码：</p>
<pre><code>$GOEXPERIMENT=loopvar go run classic_for_loop_in_1_21.go
2 3
4 5
3 4
0 1
1 2
</code></pre>
<p>我们看到了期望输出的结果。下面我使用一段等价代换代码来理解经典for loop的新语义：</p>
<pre><code>for i := 0; i &lt; 5; i++ {
    // 使用i
}

在新语义下等价于

for i := 0; i &lt; 5; i++ {
    i' := i
    // 使用i'
    i = i'
}
</code></pre>
<p>我们看到：新语义相当于Go编译器在每次iteration的前后各插入一行代码，在迭代(iteration)开始处插入i&#8217; := i，然后迭代过程中使用的是i&#8217;，而在迭代的末尾则将i&#8217;的最新值赋值给i，后续i继续参与到loop是否继续的条件判定以及后置语句的操作中去。</p>
<blockquote>
<p>注：在Go 1.21版本中使用GOEXPERIMENT=loopvar引入的新loopvar语义可能会导致遗留代码出现错误。</p>
</blockquote>
<p>到这里，我们就聊完了语言特性的变化。接下来，我们再来简单看看Go编译器和运行时的主要变化。</p>
<h2>2. Go编译器与运行时</h2>
<h3>2.1 PGO默认开启</h3>
<p><a href="https://tonybai.com/2023/02/08/some-changes-in-go-1-20">Go 1.20版本</a>引入了PGO(profile-guided optimization)优化技术预览版，Go 1.21版本中，PGO正式GA。如果main包目录下包含default.pgo文件，Go 1.21编译器在编译二进制文件时就会默认开启基于default.pgo中数据的pgo优化。优化带来的性能提升因程序而异，一般是2%~7%。</p>
<p>Go 1.21编译器自身就是基于PGO优化过的，编译速度提升约6%。</p>
<h3>2.2 大幅降低GC尾部延迟</h3>
<p>Go 1.21通过对运行时内部的GC的优化，应用程序的尾部延迟最多可减少40%，内存使用量也会略有减少。不过有些应用可能会观察到吞吐量的少量损失。内存使用量的减少与吞吐量的损失大约成正比。</p>
<h3>2.3 支持WASI(WebAssembly System Interface)</h3>
<p>Go 1.21开始支持将Go编译为支持WASI规范的wasm程序，具体可参见《<a href="https://tonybai.com/2023/04/26/go-1-21-foresight/">Go 1.21新特性前瞻</a>》。</p>
<p>不过，Go 1.21版本尚没有导出自定义函数的机制，比如：<a href="https://github.com/tetratelabs/wazero/issues/1550">在Go源代码中声明Add函数不会使得该函数在编译后的WebAssembly中被导出</a>。因此，如果使用诸如<a href="https://github.com/tetratelabs/wazero">wazero</a>这样的wasm runtime在加载Wasm后查找Add函数，将无法找到。</p>
<blockquote>
<p>注：wazero目前可以与支持导出自定义函数到wasm中的<a href="https://tinygo.org">tinygo</a>一起配合使用。</p>
</blockquote>
<p>一旦Go支持将自定义函数导出到wasm中，那么是否可以实现基于wasm的<a href="https://tonybai.com/2021/07/19/understand-go-plugin">Go应用插件机制</a>呢？wasm的执行性能如何呢？这个就留到Go支持导出函数到wasm之后再行讨论吧。</p>
<h2>3. Go工具链</h2>
<p>Go 1.21在工具链方面最值得关注的就是Go团队对向后兼容(backwards compatibility)和向前兼容(forwards compatibility)的重新思考和新措施。</p>
<p>所谓向后兼容就是用新版Go编译器可以编译遗留的历史Go代码，并可以正常运行。比如用Go 1.21版本编译器编译基于<a href="https://tonybai.com/2015/07/10/some-changes-in-go-1-5/">Go 1.5版本</a>编写的Go代码。Go在这方面做的一直很好，并提出了<a href="https://go.dev/doc/go1compat">Go1兼容性承诺</a>。</p>
<p>而向前兼容指的是用旧版编译器编译新版本Go的代码，比如用Go 1.19版本编译器编译基于Go 1.21版本编写的Go代码。显而易见，如果Go代码中使用了Go 1.21引入的新语法特性，比如clear，那么Go 1.19编译Go代码时会失败。</p>
<p>Go 1.21中对于Go工具链的向前和向后兼容又做了进一步的明确和增强，下面我们就来看一下具体的内容。</p>
<h3>3.1 向后兼容</h3>
<p>为了提高向后兼容性的体验，从Go 1.21版本开始，Go扩展和规范化了GODEBUG的使用。其大致思路如下：</p>
<ul>
<li>对于每个在Go1兼容性承诺范围内的且可能会破坏(break)现有代码的新特性/新改变(比如：panic(nil)语义的改变)加入时，Go会向GODEBUG设置中添加一个新选项(比如GODEBUG=panicnil=1)，以保留采用原语义进行编译的兼容能力；</li>
<li>GODEBUG中新增的选项将至少保留两年(4个Go release版本)，对于一些影响重大的GODEBUG选项(比如http2client和http2server)，保留的时间可能更长，甚至一直保留；</li>
<li>GODEBUG的选项设置与go.mod的go version是匹配的。例如，即便你现在的工具链是Go 1.21，如果go.mod中的go version为1.20，那么GODEBUG控制的新特性语义将不起作用，依旧保持Go 1.20时的行为。除非你将go.mod中的go version升级为go 1.21.0。下面的例子就展示了这一点：</li>
</ul>
<pre><code>// tools/godebug/go.mod
module demo

go 1.20

// tools/godebug/panicnil.go

func foo() {
    defer func() {
        if e := recover(); e != nil {
            fmt.Println("recover panic from", e)
            return
        }
        fmt.Println("panic is nil")
    }()

    panic(nil)
}

func main() {
    foo()
}
</code></pre>
<p>这个例子中go.mod中的go version为go 1.20，我们用go 1.21去编译运行该示例，得到如下结果：</p>
<pre><code>$go run panicnil.go
panic is nil
</code></pre>
<p>我们看到，即便用go 1.21编译，由于go.mod中go version为go 1.20，go 1.21对panic(nil)的语义变更并未生效。</p>
<p>如果我们将go.mod中的go version改为go 1.21.0，再运行该示例：</p>
<pre><code>$go run panicnil.go
recover panic from panic called with nil argument
</code></pre>
<p>我们看到，这次示例中的panic(nil)语义发生了变化，匹配了go 1.21对panic(nil)语义的改变。</p>
<p>在Go 1.21中，除了使用GODEBUG=panicnil=1来恢复原先语义外，还可以在main包中使用//go:debug指示符：</p>
<pre><code>// tools/godebug/panicnil.go

//go:debug panicnil=1

package main

import "fmt"

// 省略... ...
</code></pre>
<p>使用//go:debug指示符后，即便使用go 1.21编译，panic(nil)也会恢复到之前的语义。</p>
<p>很多Gopher说，历经这么多版本，GODEBUG究竟有多少了开关选项已经记不住了，没关系，Go官方文档为gopher提供了<a href="https://go.dev/doc/godebug#history">GODEBUG演进历史的文档</a>，使用时自行查阅。</p>
<p>这样，Go 1.21以后，GODEBUG就成为了应对在Go1兼容性承诺范围内，但又可能对现有代码造成破坏的change的一种标准兼容机制。</p>
<h3>3.2 向前兼容</h3>
<p>说完向后兼容，我们再来看看向前兼容，即用老编译器编译新版本代码。</p>
<p>有人会说：老编译器编译新版本代码能否编译通过并运行正常要看新版本代码中是否使用了新版本的特性。比如用<a href="https://tonybai.com/2021/02/25/some-changes-in-go-1-16">Go 1.16版本</a>编译带泛型语法的<a href="">Go 1.18</a>https://tonybai.com/2022/04/20/some-changes-in-go-1-18代码肯定是无法编译通过啊，升级一下编译器版本不就行了吗。向前兼容性的问题可能没有大家想象的这么简单。</p>
<p>如果当前代码中没有使用go 1.18中的泛型语法，使用go 1.16可以正常编译该代码，那么编译出的程序的运行行为就一定正常么？这要看Go 1.18中看似与Go 1.16版本代码兼容的部分是否有语义上的改变。如果存在这种语义上的改变，导致程序在生产中实际行为与预期行为不同，那么还不如编译失败带来的损失更小。因此，Go团队希望在向前兼容方面提供更精细化，更准确的管理手段。</p>
<p>从Go 1.21开始，go.mod文件中的go line将被当成一个<strong>约束规则</strong>。go line中的go版本号将被解释为<strong>用于编译该module时使用的最小Go语言版本</strong>，只有这个版本或其高于它的版本才能保证具有该module所需的Go语法语义。</p>
<p>Go始终允许用低版本go工具链编译go line中版本号高于工具链版本的go代码，之所以这么做，是为了避免不必要的编译失败给开发者情绪造成的影响：如果你被告知Go版本太旧无法编译程序，你肯定不会是开心的^_^。</p>
<p>但在Go 1.21之前，旧版本工具链编译新代码，有时候会构建成功(比如代码中没有使用新版本引入的新语法特性），有时会因代码中的新语法特性而构建失败。这种割裂的体验是Go团队不希望看到的，于是Go团队希望<a href="https://go.dev/blog/toolchain">将工具链的管理也纳入到go命令中</a>。</p>
<p>Go 1.21中一个最直观的变化就是当用Go 1.21编译一个go line为go 1.21.1的module时，如果本地不存在go 1.21.1工具链，go 1.21不会报错，而是去尝试下载go 1.21.1工具链到本地，如果下载成功，就会用go 1.21.1来编译这个module：</p>
<pre><code>$go run panicnil.go // 将go.mod中的go line改为1.21.1后
go: downloading go1.21.1 (darwin/amd64)
go: download go1.21.1 for darwin/amd64: toolchain not available
</code></pre>
<p>不过Go 1.21的这种自动下载新版工具链后，并不会将它安装到GOPATH/bin或覆盖当前本地安装的工具链。它会将下载的新版本工具链当作Go module，这继承了module管理的所有安全和隐私优势，然后go会从module缓存中运行下载后的工具链module。</p>
<p>除此之外，Go 1.21还在go.mod中引入了<a href="https://go.dev/doc/toolchain">toolchain指示符</a>以及GOTOOLCHAIN环境变量。一个包含了toolchain指示符的go.mod的内容如下面所示：</p>
<pre><code>// go.mod
module m

go 1.21.0
toolchain go1.21.4
</code></pre>
<p>这个go.mod中的go line含义是当其他go module依赖m时，需要至少使用go 1.21.0版本的工具链；而m模块的作者编译m时，需要了一个更新的工具链：go 1.21.4。</p>
<p>我们知道通过go get example.com/module@v1.2.1可以更新go.mod中的require block，在go 1.21版本中，我们可以使用go get go@1.21.1更新go.mod中的go line中的go version。当然以此类推，我们也可以通过go get toolchain@go1.21.1更新go.mod中的toolchain line中的工具链版本号。</p>
<p>Go工具链最终版本的选择规则较为繁琐，受到local安装的go工具链版本、GOTOOLCHAIN环境变量的设置以及go.mod中的toolchain line的综合影响，大家可以参考<a href="https://go.dev/doc/toolchain">toolchain文档</a>理解，这里就不引述了。</p>
<h2>4. Go标准库</h2>
<p>每个Go版本中变化最大的一定是标准库，这里不能一一列举所有变化，我挑了几个重要的包和大家简单分享一下。后续可能会安排专门文章对某个标准库包做专题说明。</p>
<h3>4.1 log/slog</h3>
<p>原生支持的结构化日志终于在go 1.21版本落地了，其路径为log/slog。在去年就写过一篇有关slog的文章《<a href="https://tonybai.com/2022/10/30/first-exploration-of-slog">slog：Go官方版结构化日志包</a>》，不过这近一年多以来，slog的设计和实现也都发生了一些调整，那篇文章的少部分内容可能已经不适用了。</p>
<p>关于slog值得单独写一篇新博文去专门说明，这个在后面可能会安排:)。</p>
<p>此外，Go标准库还增加了testing/slogtest包，来帮助大家验证slog.Handler的实现，这个是以前没有的。</p>
<p>slog是一个高质量、高性能的结构化日志实现，这里建议大家在启动新Go项目时，尽量采用log/slog作为日志输出的方案。</p>
<h3>4.2 slices、maps和cmp</h3>
<p>在Go实验库“孵化”了一年多的几个泛型包slices、maps和cmp终于在Go 1.21版本中正式加入到标准库中了。</p>
<p>slices切片包提供了针对切片的常用操作，slices包使用了泛型函数，可处理任何元素类型的切片。同理，maps包与slices包地位相似，只不过操作对象换成了map类型变量，它可以处理任意类型键和元素类型的map。</p>
<p>cmp包是slices包依赖的包，这个包非常简单且内聚，它仅提供了与compare和ordered相关的约束类型定义与简单泛型函数：</p>
<pre><code>// cmp包

type Ordered interface {
    ~int | ~int8 | ~int16 | ~int32 | ~int64 |
        ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
        ~float32 | ~float64 |
        ~string
}

func Less[T Ordered](x, y T) bool {
    return (isNaN(x) &amp;&amp; !isNaN(y)) || x &lt; y
}

func Compare[T Ordered](x, y T) int {
    ... ...
}

func isNaN[T Ordered](x T) bool {
    return x != x
}
</code></pre>
<p>以上三个包没有太多可说的，都是一些utils类的函数，大家在日常开发中记得用就ok了，基于泛型的实现以及unified中间代码的优化，这些函数的性能相对于基于interface实现的通用工具函数要高出一些。</p>
<blockquote>
<p>注：在Go 1.21正式版发布之前，Go team<a href="https://github.com/golang/go/issues/61538">删除了maps包中原有的Keys和Values函数</a>，其原因是要<a href="https://github.com/golang/go/issues/61405">在后续版本中提供iter包</a>。</p>
</blockquote>
<h3>4.3 其他变化</h3>
<ul>
<li>增加errors.ErrUnsupported </li>
</ul>
<p>标准库各个包都有类似unsupported的Error类型的定义，第三方包更是多如牛毛。Go 1.21在errors包中增加了ErrUnsupported，旨在统一后续对unsupported的错误判定。不过在你的函数或方法中不要直接返回errors.ErrUnsupported，要么用自定义error包装(wrap) errors.ErrUnsupported，要实现Is方法。目的是使得你自己的Error类型提供的unsupported error满足：errors.Is(err, errors.ErrUnsupported) == true。</p>
<p>http包的ErrNotSupported采用的就是实现Is方法的方式支持errors.ErrNotSupported的：</p>
<pre><code>// Is lets http.ErrNotSupported match errors.ErrUnsupported.
func (pe *ProtocolError) Is(err error) bool {
    return pe == ErrNotSupported &amp;&amp; err == errors.ErrUnsupported
}
</code></pre>
<blockquote>
<p>注：errors.ErrUnsupported这种统一对unsupported类错误处理的设计方式直接借鉴。</p>
</blockquote>
<ul>
<li>flag：增加BoolFunc函数</li>
</ul>
<p>略。</p>
<ul>
<li>net: 在linux上支持<a href="https://www.rfc-editor.org/rfc/rfc8684.html">多路径TCP</a></li>
</ul>
<p>多路径TCP协议可以让一个TCP连接在多个网络路径之间进行数据传输，从而提高传输速度和可靠性的技术。Go 1.21在linux平台上支持net包使用多路径TCP协议(如果linux kernel支持的话)。不过目前这不是默认开启的，可以通过Dialer的下面方法来显式设置：</p>
<pre><code>func (d *Dialer) SetMultipathTCP(use bool)
</code></pre>
<p>在将来的版本中，该机制很大可能会变为默认开启的。</p>
<ul>
<li>reflect：ValueOf允许在栈上分配Value的内容</li>
</ul>
<p>在Go 1.21中，ValueOf不再强制Value内容在堆上分配，而是允许在栈上分配Value的内容。对Value的大多数操作也允许在栈中分配底层值。通过其代码实现可以更好地理解这点变化：</p>
<pre><code>  // Before Go 1.21, ValueOf always escapes and a Value's content
  // is always heap allocated.
  // Set go121noForceValueEscape to true to avoid the forced escape,
  // allowing Value content to be on the stack.
  // Set go121noForceValueEscape to false for the legacy behavior
  // (for debugging).
  const go121noForceValueEscape = true

  // ValueOf returns a new Value initialized to the concrete value
  // stored in the interface i. ValueOf(nil) returns the zero Value.
  func ValueOf(i any) Value {
      if i == nil {
          return Value{}
      }

      if !go121noForceValueEscape {
          escapes(i)
      }

      return unpackEface(i)
  }
</code></pre>
<ul>
<li>sync: 增加OnceFunc, OnceValue和OnceValues等语法糖函数</li>
</ul>
<p>略。</p>
<ul>
<li>testing: 新增Testing函数</li>
</ul>
<p>Go 1.21为testing包增加了func Testing() bool函数，该函数可以用来报告当前程序是否是go test创建的测试程序。使用Testing函数，我们可以确保一些无需在单测阶段执行的函数不被执行。比如下面这个例子：</p>
<pre><code>// file/that/should/not/be/used/from/testing.go

func prodEnvironmentData() *Environment {
    if testing.Testing() {
        log.Fatal("Using production data in unit tests")
    }
    ....
}
</code></pre>
<ul>
<li>crypto/tls：增加QUICConn以支持后续的QUIC实现</li>
</ul>
<p>略。</p>
<ul>
<li>context包：新增WithoutCancel、WithDeadlineCause、WithTimeoutCause和AfterFunc </li>
</ul>
<p>新增的WithoutCancel、WithDeadlineCause、WithTimeoutCause函数可以让你通过Cause函数获得导致cancel/timeout的真因：</p>
<pre><code>ctx, cancel := context.WithCancelCause(parent)
cancel(myError)
ctx.Err() // returns context.Canceled
context.Cause(ctx) // returns myError
</code></pre>
<p>AfterFunc函数是一个高级函数，与time.AfterFunc的机制和用法都类似，<a href="https://pkg.go.dev/context#AfterFunc">官方文档中有三个使用AfterFunc的例子</a>，大家可以移步过去看看，这里就不赘述了。</p>
<ul>
<li>runtime/trace：收集跟踪信息成本大幅降低</li>
</ul>
<p>现在，trace在amd64和arm64上收集跟踪信息所需的CPU成本大幅降低：与上一版本相比，最多可提高10倍。</p>
<ul>
<li>unicode: 升级到Unicode 15.0.0版本</li>
</ul>
<p>略。</p>
<h2>5. 小结</h2>
<p>个人觉得：Go 1.21是一个重要的“大”版本，它对Go语言后续的演进有着重大影响，尤其是对向前兼容和向后兼容的思考和手段的提供，为后续Go演进奠定了基础，即便这些规则读起来和理解起来有些复杂^_^。</p>
<p>本文示例代码可以在<a href="https://github.com/bigwhite/experiments/blob/master/go1.21-examples">这里</a>下载。</p>
<h2>6. 参考资料</h2>
<ul>
<li>Go 1.21 Release Notes &#8211; https://go.dev/doc/go1.21</li>
<li>Go 1.21版本发布 &#8211; https://go.dev/blog/go1.21</li>
<li>Backward Compatibility, Go 1.21, and Go 2 &#8211; https://go.dev/blog/compat</li>
<li>Forward Compatibility and Toolchain Management in Go 1.21 &#8211; https://go.dev/blog/toolchain</li>
<li>Godebug手册 &#8211; https://go.dev/doc/godebug</li>
<li>LoopvarExperiment &#8211; https://github.com/golang/go/wiki/LoopvarExperiment</li>
<li>How Golang Evolves without Breaking Programs &#8211; https://thenewstack.io/how-golang-evolves-without-breaking-programs</li>
<li>PGO user guide &#8211; https://go.dev/doc/pgo</li>
</ul>
<hr />
<p><a href="https://public.zsxq.com/groups/51284458844544">“Gopher部落”知识星球</a>旨在打造一个精品Go学习和进阶社群！高品质首发Go技术文章，“三天”首发阅读权，每年两期Go语言发展现状分析，每天提前1小时阅读到新鲜的Gopher日报，网课、技术专栏、图书内容前瞻，六小时内必答保证等满足你关于Go语言生态的所有需求！2023年，Gopher部落将进一步聚焦于如何编写雅、地道、可读、可测试的Go代码，关注代码质量并深入理解Go核心技术，并继续加强与星友的互动。欢迎大家加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-tribe-zsxq-small-card.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/go-programming-from-beginner-to-master-qr.png" alt="img{512x368}" /></p>
<p><img src="http://image.tonybai.com/img/tonybai/go-first-course-banner.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/imooc-go-column-pgo-with-qr.jpg" alt="img{512x368}" /></p>
<p>著名云主机服务厂商DigitalOcean发布最新的主机计划，入门级Droplet配置升级为：1 core CPU、1G内存、25G高速SSD，价格5$/月。有使用DigitalOcean需求的朋友，可以打开这个<a href="https://m.do.co/c/bff6eed92687">链接地址</a>：https://m.do.co/c/bff6eed92687 开启你的DO主机之路。</p>
<p>Gopher Daily(Gopher每日新闻) &#8211; https://gopherdaily.tonybai.com</p>
<p>我的联系方式：</p>
<ul>
<li>微博(暂不可用)：https://weibo.com/bigwhite20xx</li>
<li>微博2：https://weibo.com/u/6484441286</li>
<li>博客：tonybai.com</li>
<li>github: https://github.com/bigwhite</li>
<li>Gopher Daily归档 &#8211; https://github.com/bigwhite/gopherdaily</li>
</ul>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。</p>
<p style='text-align:left'>&copy; 2023, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2023/08/20/some-changes-in-go-1-21/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>2022年Go语言盘点：泛型落地，无趣很好，稳定为王</title>
		<link>https://tonybai.com/2022/12/29/the-2022-review-of-go-programming-language/</link>
		<comments>https://tonybai.com/2022/12/29/the-2022-review-of-go-programming-language/#comments</comments>
		<pubDate>Thu, 29 Dec 2022 14:05:03 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[2022]]></category>
		<category><![CDATA[boring]]></category>
		<category><![CDATA[Cpp]]></category>
		<category><![CDATA[generics]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[go-module]]></category>
		<category><![CDATA[go1.18]]></category>
		<category><![CDATA[go1.21]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GopherCon]]></category>
		<category><![CDATA[Go语言第一课]]></category>
		<category><![CDATA[hertz]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[kitex]]></category>
		<category><![CDATA[maps]]></category>
		<category><![CDATA[netpoll]]></category>
		<category><![CDATA[PGO]]></category>
		<category><![CDATA[RobPike]]></category>
		<category><![CDATA[RussCox]]></category>
		<category><![CDATA[slices]]></category>
		<category><![CDATA[slog]]></category>
		<category><![CDATA[stable]]></category>
		<category><![CDATA[TIOBE]]></category>
		<category><![CDATA[字节]]></category>
		<category><![CDATA[泛型]]></category>
		<category><![CDATA[盘点]]></category>
		<category><![CDATA[稳定]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=3767</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2022/12/29/the-2022-review-of-go-programming-language 早早就计划好在年前写一个Go语言年度盘点，就像2020年和2021年那样。但恰逢国内疫情管控放开，一波阳了之后身体十分容易疲劳，再加上工作上的事情挺多，这篇盘点也就迟迟没能下笔。 今年的盘点思路将围绕三个关键字来展开：泛型、无趣(boring)和稳定。下面我们逐一来看看。 1. “泛型”靴子落地 2022年3月中旬，Go社区尤其是那些期盼Go加入泛型特性的Gopher终于迎来了Go 1.18版本的正式发布，这意味着Go泛型这只靴子终于落地了。 其实，从Go开源那一天开始，Go核心团队就没有间断过对泛型的探索，并一直尝试寻找一个理想的泛型设计方案，但始终未能如愿。直到近几年Go团队觉得Go已经逐渐成熟，是时候下决心解决Go社区主要关注的几个问题了，包括泛型、包依赖以及错误处理等。其中泛型常年在Go官方用户调查报告的“你最想要的Go语言特性”这项调查的榜单上霸榜，下图摘自2020年度Go官方用户调查结果： 之后，Go团队安排伊恩·泰勒和罗伯特·格瑞史莫花费更多精力在泛型的设计方案上，这才有了Go 1.18 版本中泛型语法特性的落地。 个人觉得：Go泛型是Go核心团队对Go社区的一次迎合与妥协，因为泛型与Go的主要设计哲学“简单”是有悖的。泛型这个语法特性会给语言带来复杂性，这种复杂性不仅体现在语法层面上引入了难于理解和使用的新的语法元素，也体现在类型系统和运行时层面上为支持泛型进行的复杂的实现。 如果从2010年6月份，伊恩·泰勒提出的Type Functions设计方案算起，到2022年3月份的泛型落地，Go加入泛型之路足足走了近12年。不过结果还是不错的，经过近12年的努力与不断地自我否定，Go团队终于找到了一个不违背Go1兼容性承诺(见下图)的泛型实现方案： 从这方面讲，Go对泛型的支持又是十分成功的。在如此语法巨变的情况下，依然保持向后兼容(backforward compatibility)。 不过如果你因为Go加入了对泛型的支持就打算投入Go阵营，这里先给你一些友情提示：和支持泛型的主流编程语言之间的泛型设计与实现存在差异一样，Go的泛型与其他主流编程语言的泛型也是不同的。在学习Go泛型之前，可以先了解一下Go泛型设计方案已经明确不支持的若干特性，比如： 不支持泛型特化（specialization），即不支持编写一个泛型函数针对某个具体类型的特殊版本； 不支持元编程（metaprogramming），即不支持编写在编译时执行的代码来生成在运行时执行的代码； 不支持操作符方法（operator method），即只能用普通的方法（method）操作类型实例（比如：getIndex(k)），而不能将操作符视为方法并自定义其实现，比如一个容器类型的下标访问 c[k]； 不支持变长的类型参数（type parameters）； &#8230; &#8230;。 这些特性如今不支持，后续大概率也不会支持。所以小伙伴们，尤其是来自Java、C++等语言阵营的小伙伴，在进入Go泛型语法学习之前，你一定要先了解Go团队的这些设计决策。 此外，目前的Go泛型实现和最后一版的泛型设计方案相比还有差距，依旧不是完全版，还有一些特性没有加入，还有问题亟待解决。 就目前笔者观察来看，Go泛型还处于早期阶段，远非成熟。Go module构建模式从go 1.11版本加入到go 1.16成为默认并逐渐成熟还花了3年多时间呢，何况是Go泛型。这样来看，初步预测Go泛型要到2025年才会成熟，而成熟的标志无非如下几个： 泛型语法特性确定以及稳定下来； 语法问题基本都解决； Go标准库开始广泛使用泛型； Go泛型的运行时性能问题得到基本解决。 目前Go团队对泛型的应用依旧保持谨慎，并在循序渐进地推进泛型在Go团队与Go社区的应用，最新的消息是Go团队已经提出proposal，计划在Go 1.21版本中将用泛型实现的maps包和slices包加入Go标准库，这两个包原本计划在Go 1.18版本加入，但因Rob Pike的建议先放到了golang.org/x/exp下面待定。 2. 无趣(boring)很好 和其他主流编程语言如C++、Rust等在新版本中不断有新语言特性刺激程序员的神经，让大家阶段性产生兴奋感(exciting)不同，除了早期版本(比如Go 1.1和Go 1.2)以及里程碑的Go 1.5版本的完成自举和大幅降低GC延迟、Go 1.11版本的go module构建模式、Go 1.18版本的泛型落地之外，大部分版本的发布都很难让Gopher们十分兴奋，甚至业界都称“Go is boring(Go很无趣)”。 在今年的线下GopherCon大会上，Go核心团队技术Leader Russ [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/the-2022-review-of-go-programming-language-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2022/12/29/the-2022-review-of-go-programming-language">本文永久链接</a> &#8211; https://tonybai.com/2022/12/29/the-2022-review-of-go-programming-language</p>
<p>早早就计划好在年前写一个Go语言年度盘点，就像<a href="https://tonybai.com/2020/12/30/the-2020-review-of-go-programming-language">2020年</a>和<a href="https://tonybai.com/2022/01/16/the-2021-review-of-go-programming-language">2021年</a>那样。但恰逢国内疫情管控放开，一波阳了之后身体十分容易疲劳，再加上工作上的事情挺多，这篇盘点也就迟迟没能下笔。</p>
<p>今年的盘点思路将围绕三个关键字来展开：<strong>泛型、无趣(boring)和稳定</strong>。下面我们逐一来看看。</p>
<h3>1. “泛型”靴子落地</h3>
<p>2022年3月中旬，Go社区尤其是那些期盼Go加入泛型特性的Gopher终于迎来了<a href="https://tonybai.com/2022/03/16/go-1-18-released">Go 1.18版本的正式发布</a>，这意味着<strong>Go泛型这只靴子终于落地了</strong>。</p>
<p>其实，从Go开源那一天开始，Go核心团队就没有间断过对泛型的探索，并一直尝试寻找一个理想的泛型设计方案，但始终未能如愿。直到近几年Go团队觉得Go已经逐渐成熟，是时候下决心解决Go社区主要关注的几个问题了，包括泛型、包依赖以及错误处理等。其中泛型常年在Go官方用户调查报告的“你最想要的Go语言特性”这项调查的榜单上霸榜，下图摘自2020年度Go官方用户调查结果：</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2022-review-of-go-programming-language-7.png" alt="" /></p>
<p>之后，Go团队安排伊恩·泰勒和罗伯特·格瑞史莫花费更多精力在泛型的设计方案上，这才有了Go 1.18 版本中泛型语法特性的落地。</p>
<p>个人觉得：Go泛型是Go核心团队对Go社区的一次迎合与妥协，因为泛型与Go的主要设计哲学“简单”是有悖的。泛型这个语法特性会给语言带来复杂性，这种复杂性不仅体现在语法层面上引入了<strong>难于理解和使用</strong>的新的语法元素，也体现在类型系统和运行时层面上为支持泛型进行的复杂的实现。</p>
<p>如果从2010年6月份，伊恩·泰勒提出的<a href="https://go.googlesource.com/proposal/+/master/design/15292/2010-06-type-functions.md">Type Functions设计方案</a>算起，到2022年3月份的泛型落地，<a href="https://time.geekbang.org/column/article/485140">Go加入泛型之路足足走了近12年</a>。不过结果还是不错的，经过近12年的努力与不断地自我否定，Go团队终于找到了一个不违背<strong><a href="https://go.dev/doc/go1compat">Go1兼容性承诺(见下图)</a></strong>的<a href="https://github.com/golang/proposal/blob/master/design/43651-type-parameters.md">泛型实现方案</a>：</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2022-review-of-go-programming-language-4.png" alt="" /></p>
<p>从这方面讲，Go对泛型的支持又是十分成功的。在如此语法巨变的情况下，依然保持向后兼容(backforward compatibility)。</p>
<p>不过如果你因为Go加入了对泛型的支持就打算投入Go阵营，这里先给你一些友情提示：<strong>和支持泛型的主流编程语言之间的泛型设计与实现存在差异一样，Go的泛型与其他主流编程语言的泛型也是不同的</strong>。在学习Go泛型之前，可以先了解一下Go泛型设计方案已经明确不支持的若干特性，比如：</p>
<ul>
<li>不支持泛型特化（specialization），即不支持编写一个泛型函数针对某个具体类型的特殊版本；</li>
<li>不支持元编程（metaprogramming），即不支持编写在编译时执行的代码来生成在运行时执行的代码；</li>
<li>不支持操作符方法（operator method），即只能用普通的方法（method）操作类型实例（比如：getIndex(k)），而不能将操作符视为方法并自定义其实现，比如一个容器类型的下标访问 c[k]；</li>
<li>不支持变长的类型参数（type parameters）；</li>
<li>&#8230; &#8230;。</li>
</ul>
<p>这些特性如今不支持，后续大概率也不会支持。所以小伙伴们，尤其是来自Java、C++等语言阵营的小伙伴，在进入Go泛型语法学习之前，你一定要先了解Go团队的这些设计决策。</p>
<p>此外，目前的Go泛型实现和最后一版的<a href="https://github.com/golang/proposal/blob/master/design/43651-type-parameters.md">泛型设计方案</a>相比还有差距，依旧不是完全版，还有一些特性没有加入，<a href="https://go101.org/generics/888-the-status-quo-of-go-custom-generics.html">还有问题亟待解决</a>。</p>
<p>就目前笔者观察来看，Go泛型还处于早期阶段，远非成熟。Go module构建模式从<a href="https://tonybai.com/2018/11/19/some-changes-in-go-1-11">go 1.11版本</a>加入到<a href="https://tonybai.com/2021/02/25/some-changes-in-go-1-16">go 1.16</a>成为默认并逐渐成熟还花了3年多时间呢，何况是Go泛型。这样来看，初步预测Go泛型要到2025年才会成熟，而成熟的标志无非如下几个：</p>
<ul>
<li>泛型语法特性确定以及稳定下来；</li>
<li>语法问题基本都解决；</li>
<li>Go标准库开始广泛使用泛型；</li>
<li>Go泛型的运行时性能问题得到基本解决。</li>
</ul>
<p>目前Go团队对泛型的应用依旧保持谨慎，并在循序渐进地推进泛型在Go团队与Go社区的应用，最新的消息是Go团队已经提出proposal，计划在Go 1.21版本中将用泛型实现的<a href="https://github.com/golang/go/issues/57436">maps包</a>和<a href="https://github.com/golang/go/issues/57433">slices包</a>加入Go标准库，这两个包原本计划在Go 1.18版本加入，但因Rob Pike的建议先放到了golang.org/x/exp下面待定。</p>
<h3>2. 无趣(boring)很好</h3>
<p>和其他主流编程语言如C++、Rust等在新版本中不断有新语言特性刺激程序员的神经，让大家阶段性产生兴奋感(exciting)不同，除了早期版本(比如Go 1.1和Go 1.2)以及里程碑的Go 1.5版本的完成自举和大幅降低GC延迟、Go 1.11版本的go module构建模式、Go 1.18版本的泛型落地之外，大部分版本的发布都很难让Gopher们十分兴奋，甚至业界都称<strong>“Go is boring(Go很无趣)”</strong>。</p>
<p>在今年的线下GopherCon大会上，Go核心团队技术Leader Russ Cox发表名为<a href="https://www.youtube.com/watch?v=v24wrd3RwGo">“Compatibility: How Go Programs Keep Working”</a>的主题演讲，在这个演讲中，Russ Cox借用了Go is boring的这一说法，并称That is good!</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2022-review-of-go-programming-language-3.png" alt="" /></p>
<blockquote>
<p>国外新冠管控放开早，经过几波疫情后，与病毒共存了，于是2022年的GopherCon大会又重新恢复线下举办。</p>
</blockquote>
<p>Russ Cox的原话是：“boring is good. boring is stable. boring means to be able to focus on your work and not ours&#8230; We&#8217;ll keep doing everything we can to keep go boring for all of you”。</p>
<p>这几句英文不难，相信大家都能看懂。无趣的Go意味着稳定，意味着大家将注意力都集中在自己的工作上而不是Go核心团队身上(去关注新特性)。Go语言不会像其他编程语言那样堆砌新功能特性。</p>
<p>Russ Cox的这一观点代表了Go核心团队，也代表着Go演进未来演进的主基调。同时，Russ明确给出结论：<strong>不会有Go2了</strong>，Go 1.xy会一直持续下去。Russ甚至提出：<strong>兼容性才是Go最重要的feature</strong>：</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2022-review-of-go-programming-language-6.png" alt="" /></p>
<p>并且Russ Cox在Go项目的discussion中也给出保持Go兼容性的<a href="https://github.com/golang/go/discussions/55090">backward compatibility</a>、<a href="https://github.com/golang/go/discussions/55092">forward compatibility</a>的扩展方案与<a href="https://github.com/golang/go/discussions/56010">一个实例</a>。</p>
<p>关于“Go is boring”，Russ没有进一步展开说，记得之前译过一篇名为<a href="https://tonybai.com/2021/01/07/go-is-boring">《Go语言很无聊&#8230;其实它妙不可言！》</a>的文章，大家可以看看那篇文章进一步体会一下“Go is boring”的含义。</p>
<h3>3. “稳定”是主旋律</h3>
<p>Go的稳定不仅体现在Go语法特性的演化上，Go语言在各大语言排行榜上的排名也进入了相对稳定区，以<a href="https://www.tiobe.com/tiobe-index/">TIOBE index</a>为例，下面是2022年12月份的排名截图：</p>
<p><img src="https://tonybai.com/wp-content/uploads/the-2022-review-of-go-programming-language-2.png" alt="" /></p>
<blockquote>
<p>我查了一下《<a href="https://tonybai.com/2022/01/16/the-2021-review-of-go-programming-language">2021年Go语言盘点：厉兵秣马强技能，蓄势待发新征程</a>》一文中2022年1月份Go的排名为13名，上图中2021年12月份是19名的数据应该是错误的，相对2021年12月份，Go实际排名上升1位。</p>
</blockquote>
<p>我们看到2021年Go从14升到13，今年又从13升到12。按照TIOBE官方编辑说法，在新兴编程语言中，Go是唯一一个可能在未来冲入前十的后端编程语言。</p>
<p>Go语言在实际应用中的表现与上述排名的变化也十分契合，总体来说就是十分稳定，国内外都波澜不惊，国内大厂该用Go的也都用了，腾讯、字节依旧是这方面的领头羊，先后开源了不少Go实现的项目，最受瞩目的应该是字节将内部的Go框架逐一开源了，包括：<a href="https://github.com/cloudwego/netpoll">netpoll</a>、<a href="https://github.com/cloudwego/kitex">kitex(rpc框架)</a>、<a href="https://github.com/cloudwego/hertz">hertz(http框架)</a>等。</p>
<p>为了更好的帮助大家回顾这一年来Go的稳定演化，这里简单整理了2022年Go大事件列表，供大家参考：</p>
<ul>
<li>2022年3月，<a href="https://tonybai.com/2022/04/20/some-changes-in-go-1-18">Go 1.18版本正式发布</a></li>
</ul>
<p>Go社区等待了多年的泛型语法特性终于加入Go中。</p>
<ul>
<li>2022年4月，Go官方发布了<a href="https://go.dev/blog/survey2021-results">2021官方Go用户调查结果</a></li>
</ul>
<p>从调查结果中可以看到，Gopher对Go的满意度依然高达92%；81%的受访者对Go项目的长期方向充满信心。</p>
<ul>
<li>2022年5月，ACM期刊发表了<a href="https://tonybai.com/2022/05/04/the-paper-of-go-programming-language-and-environment">《Go编程语言与环境》</a>一文</li>
</ul>
<p>这篇Go语言的综述文章由Russ Cox，Robert Griesemer，Rob Pike，Ian Lance Taylor和Ken Thompson联合撰写，是<strong>Go核心团队对10多年来Go演化发展的复盘</strong>，深入分析了那些对Go的成功最具决定性的设计哲学与决策，是Go诞生十多年来最重要的一篇文章。</p>
<ul>
<li>2022年6月，uber工程博客发布<a href="https://tonybai.com/2022/06/21/data-race-detection-and-pattern-in-go">《Go语言数据竞争检测与数据竞争模式》</a></li>
</ul>
<p>该文介绍了ThreadSanitizer v2的工作原理，并总结了7类数据竞争模式。</p>
<ul>
<li>2022年8月，<a href="https://tonybai.com/2022/08/22/some-changes-in-go-1-19">Go 1.19版本正式发布</a></li>
</ul>
<p>相对于Go 1.18版本而言，Go 1.19是一个“小”版本，它主要针对Go 1.18版本中泛型实现的问题做了修改和优化，引入了Soft memory limit，更新了<a href="https://go.dev/ref/mem">《Go内存模型》</a>文档。</p>
<ul>
<li>2022年9月，<a href="https://go.dev/blog/go119runtime">Go官方回顾了从2018年到2022年，Go runtime的主要改进点</a></li>
</ul>
<p>包括sync.Pool的优化、defer性能提升、基于系统信号的抢占式调度(go 1.14)、调度器性能提升、支持<a href="https://tonybai.com/2021/08/20/using-register-based-calling-convention-in-go-1-17">基于寄存器的调用规约</a>、soft memory limit等。</p>
<ul>
<li>2022年9月，Go官方发布<a href="https://tonybai.com/2022/09/10/an-intro-of-govulncheck">govulncheck工具</a></li>
</ul>
<p><a href="https://tonybai.com/2022/03/14/software-supply-chain-security-in-go">软件供应链安全问题</a>愈发受到各界关注。Go安全团队发布Go官方安全漏洞管理的工具和方案: govulncheck。govulncheck是<a href="https://vuln.go.dev">Go安全漏洞数据库(Go vulnerability database)</a>的一个<strong>前端</strong>，它通过<a href="https://github.com/golang/vuln">Go官方维护的vuln仓库</a>下面的<a href="https://github.com/golang/vuln/tree/master/vulncheck">vulncheck包</a>对你仓库中的Go源码或编译 后的Go应用可执行二进制文件进行扫描，形成源码的调用图(callgraph)和调用栈(callstack)。</p>
<ul>
<li>2022年10月，GopherCon大会在芝加哥线下举行</li>
</ul>
<p>Russ Cox发表《Compatibility: How Go Programs Keep Working》主题演讲，确定了未来Go语言演进的主基调。</p>
<ul>
<li>2022年11月，Go开源13岁生日</li>
</ul>
<p>Go官方回顾了2022年Go团队的工作与成果，并简单说明了在新一年的工作，包括继续努力使Go成为用于大规模软件工程的最好的环境。计划特别关注供应链安全，提高兼容性和结构化日志记录(<a href="https://tonybai.com/2022/10/30/first-exploration-of-slog">slog</a>)，当然还会有很多其他改进，包括<a href="https://github.com/golang/go/issues/55022">profile-guided optimization</a>等。</p>
<h3>4. Go语言2023年展望</h3>
<p>目前Go语言的演化与发展与我在<a href="https://tonybai.com/2020/12/30/the-2020-review-of-go-programming-language/">2020年Go盘点</a>中的预测基本一致。我现在依然坚持我的判断，即我在<a href="http://gk.link/a/10AVZ">《Go语言第一课》专栏</a>中所说的那样：</p>
<blockquote>
<p>绝大多数主流编程语言将在其诞生后的第15至第20年间大步前进。按照这个编程语言的一般规律，已经迈过开源第13个年头的Go，很可能将进入自己的黄金5-10年。2022年泛型落地就是Go语言进入黄金5-10年的起点，待2025年泛型成熟后，Go将取得更快的发展速度。</p>
</blockquote>
<p>前途是美好的，但道路的曲折坎坷的。目前Go更多应用于基础设施、中间件领域和基础微服务领域，在企业级业务系统方面，类似spring这样的“全家桶”框架的缺乏和无法达成一致，让开发者在开发复杂业务系统时依旧首选Java。期待Go在这方面能所有进展。</p>
<p>同时，Go演进道路上还存在另外一个风险，在我的<a href="https://tonybai.com/2022/12/07/why-go-succeed">《Go为什么能成功》</a>一文中，我曾经提到过：“Go成也Google，败也Google”。Go团队目前的治理体系太过于依赖google，这是一门双刃剑。当google发展较好时，Go语言将从中受益。但当google开始走下坡路时，Go是否还能像如今这样风光呢？让我么拭目以待吧！</p>
<hr />
<p><a href="https://wx.zsxq.com/dweb2/index/group/51284458844544">“Gopher部落”知识星球</a>旨在打造一个精品Go学习和进阶社群！高品质首发Go技术文章，“三天”首发阅读权，每年两期Go语言发展现状分析，每天提前1小时阅读到新鲜的Gopher日报，网课、技术专栏、图书内容前瞻，六小时内必答保证等满足你关于Go语言生态的所有需求！2022年，Gopher部落全面改版，将持续分享Go语言与Go应用领域的知识、技巧与实践，并增加诸多互动形式。欢迎大家加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-tribe-zsxq-small-card.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/go-programming-from-beginner-to-master-qr.png" alt="img{512x368}" /></p>
<p><img src="http://image.tonybai.com/img/tonybai/go-first-course-banner.png" alt="img{512x368}" /><br />
<img src="http://image.tonybai.com/img/tonybai/imooc-go-column-pgo-with-qr.jpg" alt="img{512x368}" /></p>
<p><a href="https://tonybai.com/">我爱发短信</a>：企业级短信平台定制开发专家 https://tonybai.com/。smspush : 可部署在企业内部的定制化短信平台，三网覆盖，不惧大并发接入，可定制扩展； 短信内容你来定，不再受约束, 接口丰富，支持长短信，签名可选。2020年4月8日，中国三大电信运营商联合发布《5G消息白皮书》，51短信平台也会全新升级到“51商用消息平台”，全面支持5G RCS消息。</p>
<p>著名云主机服务厂商DigitalOcean发布最新的主机计划，入门级Droplet配置升级为：1 core CPU、1G内存、25G高速SSD，价格5$/月。有使用DigitalOcean需求的朋友，可以打开这个<a href="https://m.do.co/c/bff6eed92687">链接地址</a>：https://m.do.co/c/bff6eed92687 开启你的DO主机之路。</p>
<p>Gopher Daily(Gopher每日新闻)归档仓库 &#8211; https://github.com/bigwhite/gopherdaily</p>
<p>我的联系方式：</p>
<ul>
<li>微博(暂不可用)：https://weibo.com/bigwhite20xx</li>
<li>微博2：https://weibo.com/u/6484441286</li>
<li>博客：tonybai.com</li>
<li>github: https://github.com/bigwhite</li>
</ul>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。</p>
<p style='text-align:left'>&copy; 2022, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2022/12/29/the-2022-review-of-go-programming-language/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
