标签 垃圾回收 下的文章

“Go is badly designed”?它像极了我们当年恨过的物理老师!

本文永久链接 – https://tonybai.com/2025/04/17/go-is-badly-designed

大家好,我是Tony Bai。

今天刷X (前Twitter) 的时候,看到Golang Insiders社区下面这条推文,真是差点扑哧一声笑出来,感觉说得太形象了,必须分享给大家:

这位叫Lyes的开发者回应 “Go is badly designed” (Go 语言设计得很糟糕) 的说法,他打了个比方:

这让我想起了我的高中物理老师,我们当时都恨他,因为他从不‘放水’简化物理知识。课难、考试难,大部分人在他手下分数都不高,所以他自然成了‘坏老师’。

Go 语言就有点像他。它从不‘放水’,直面问题。你可以很快用它变得高效,写出远比用 Python 或 JavaScript 写得更好的软件。

但你也得知道,这门语言不会‘溺爱’你。当你的服务器因为一个 nil map 或其他新手常犯的错误而 panic 时,别生气。

不像 Rust,Go 的编译器不会在你编程生涯的每一刻都‘牵着你的手’。它会给你足够的方向让你知道该往哪走,满足你 80% 的需求,同时仍然保持你的生产力。

怎么样?看完这段话,是不是像极了我们初学Go时,被nil pointer dereference 或 index out of range 当头棒喝的瞬间? 像极了我们当年一边抱怨物理老师太严格、考试太变态,一边又不得不硬着头皮去啃那些公式和定理的样子?

Lyes 的这个比喻,可以说精准地戳中了 Go 语言的一些核心特质,也解释了为什么关于“Go是否设计糟糕”的争论从未停止。咱们今天就借着这个“物理老师”的比喻,好好聊聊Go的“坏脾气”和它背后的设计哲学。

那个从不“放水”的“严格老师”

Lyes 说 Go 不会 “dumb down anything(简化任何事物,去除复杂性)”,这太对了。Go语言的设计哲学里,“简洁”(Simplicity) 是核心原则之一,但这不代表“简单化”到隐藏问题的程度。相反,它选择直面问题

  • 显式的错误处理 (if err != nil):不像某些语言用try-catch将错误“藏”起来,Go强迫你几乎在每次可能出错的操作后都检查错误。这很“烦”,但它逼着你思考每一步潜在的风险,就像物理老师逼着你弄懂每个公式的推导过程。

  • 直白的运行时Panic:当你对一个 nil 的 map 或 slice 进行操作时,Go 不会帮你“优雅地”处理,而是直接给你一个运行时 panic,程序崩溃。这很“粗暴”,但它用最直接的方式告诉你:“同学,你这里犯了个基础错误,赶紧改!” 这不就是物理老师发现你基本概念没搞懂时,直接点名批评,让你印象深刻吗?

  • 没有“溺爱”的语法糖:相比一些现代语言,Go 的语法糖相对较少。它没有泛滥的操作符重载,没有复杂的隐式转换。很多事情需要你明确地写出来。这让代码有时候显得“啰嗦”,但大大降低了阅读和理解他人代码时的歧义,保证了大规模团队协作的效率。就像物理老师坚持用标准的符号和单位,不允许自创“简写”,是为了保证科学的严谨性。

“坏老师”真的“坏”吗?—— 严格背后的价值

我们当年可能都偷偷抱怨过物理老师不近人情,但多年后回想,是不是反而感谢他的严格,才让我们打下了坚实的基础?Go 语言的“严格”同样如此:

  1. 逼你养成好习惯:被 nil panic 搞崩溃几次后,你自然就学会了在使用 map/slice/pointer 前做检查,学会了初始化,学会了更严谨地思考边界条件。这种被“教训”出来的习惯,最终会融入你的编程血液,让你写出更健壮、更可靠的代码。这比那些“温柔”地帮你掩盖了问题,直到生产环境才爆发出更大危机的语言,是不是长期来看更负责任?

  2. 简单直白,易于掌握核心:虽然会“当头棒喝”,但Go的核心概念相对较少,语法简洁。一旦你掌握了它的规则(比如错误处理模式、接口哲学、goroutine的使用),就能快速上手,并且写出的代码风格差异不会太大,易于团队维护。它不像某些语言,特性繁多,学习曲线陡峭,精通需要漫长时间。Go就像物理老师划定的核心考点,虽然难,但范围明确,努力就有回报。

  3. 效率与务实:给你“80%的指引”:Lyes 提到了Go与Rust的对比,说Go不会“全程牵手”。这正是Go的务实之处。它在编译速度、开发效率和运行时安全之间做了一个取舍。它通过快速编译、垃圾回收、简洁的并发模型,让你能高效地构建系统,满足大部分(比如 80%)场景的需求。它相信开发者是成年人,应该为自己的代码负责,而不是让编译器承担所有检查的重任。这就像物理老师教会你核心原理和解题方法,但不会一步步带着你做完所有练习题,他相信你能举一反三,独立解决问题。

不是“设计糟糕”,而是哲学不同

所以,“Go is badly designed” 吗?

与其说是“糟糕”,不如说是设计哲学和目标受众的不同

  • 如果你期望一门语言能像 Rust 那样,在编译期就为你消除几乎所有内存安全和并发风险,愿意为此付出更陡峭的学习曲线和更长的编译时间,那么 Go 可能确实“不够好”。
  • 但如果你追求的是快速构建、高效部署、简单可靠、易于维护的大型后端系统,能接受在运行时处理一些本可避免的错误(并通过良好的实践和工具来减少它们),那么Go的设计哲学可能恰恰是它的优点

Go 就像那位严格的物理老师,他可能不会让你在学习过程中时刻感到“舒适”,甚至会让你经历挫败和“阵痛”。但他目标明确,方法直接,逼着你打好基础,养成严谨的习惯,最终让你能够独立、高效地解决实际问题。

那么,你怎么看?

  • 你觉得Go语言像不像你当年“恨过”的某位老师?
  • 你第一次遇到 nil panic 时是什么感受?是觉得Go设计糟糕,还是反思自己代码的问题?
  • 你更喜欢 Go 这种“给你方向,但不全程牵手”的方式,还是 Rust 那种“无微不至的保护”?

欢迎在评论区留下你的看法,分享你和 Go “相爱相杀”的故事!


原「Gopher部落」已重装升级为「Go & AI 精进营」知识星球,快来加入星球,开启你的技术跃迁之旅吧!

我们致力于打造一个高品质的 Go 语言深度学习AI 应用探索 平台。在这里,你将获得:

  • 体系化 Go 核心进阶内容: 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏,夯实你的 Go 内功。
  • 前沿 Go+AI 实战赋能: 紧跟时代步伐,学习「Go+AI应用实战」、「Agent开发实战课」,掌握 AI 时代新技能。
  • 星主 Tony Bai 亲自答疑: 遇到难题?星主第一时间为你深度解析,扫清学习障碍。
  • 高活跃 Gopher 交流圈: 与众多优秀 Gopher 分享心得、讨论技术,碰撞思想火花。
  • 独家资源与内容首发: 技术文章、课程更新、精选资源,第一时间触达。

衷心希望「Go & AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚,享受技术精进的快乐!欢迎你的加入!

img{512x368}
img{512x368}
img{512x368}

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格6$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻) – https://gopherdaily.tonybai.com

我的联系方式:

  • 微博(暂不可用):https://weibo.com/bigwhite20xx
  • 微博2:https://weibo.com/u/6484441286
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • Gopher Daily归档 – https://github.com/bigwhite/gopherdaily
  • Gopher Daily Feed订阅 – https://gopherdaily.tonybai.com/feed

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

Go开发者必看!Uber如何利用PGO将Go服务性能优化推向新高度?

本文永久链接 – https://tonybai.com/2025/04/11/uber-go-pgo-optimization

对于像Uber这样广泛采用Go语言(Uber 60%的CPU资源都用于支撑Go服务运行)的科技巨头而言,性能优化不仅关乎用户体验,更直接影响着运营成本。继多年前通过GOGC调优节省7万CPU核心后,Uber近期再次发力,分享了其在大规模Go服务中部署Profile-Guided Optimization (PGO) 的实践经验,并通过自动化框架和工具创新,克服了关键挑战,实现了显著的性能收益。在这篇文章中,我就来介绍一下Uber的PGO优化之旅,供大家参考。

1. PGO:Go近几个版本持续投入的性能优化手段

Profile-Guided Optimization (PGO),即配置文件引导的优化,是一种利用程序实际运行时的性能分析数据(Profile)来指导编译器进行优化的技术。相比传统的静态分析和启发式规则,PGO能够让编译器更精准地识别热点代码路径、函数调用频率、分支预测等,从而做出更优的优化决策,例如:

  • 更智能的函数内联(Inlining): 基于实际调用频率,更精确地决定内联哪些“热”函数,即便这些函数在常规编译时可能不会被内联,从而减少函数调用开销。
  • 接口调用的去虚拟化(Devirtualization): 在PGO数据表明接口变量在运行时通常指向特定具体类型时,可以将动态派发转换为更高效的直接调用。
  • 优化的代码布局: 通过基本块重排、函数分割、函数重排等,改善指令缓存(iCache)和TLB的命中率,减少CPU前端停顿。

Go语言自Go 1.20版本开始引入对PGO的支持(最初侧重于内联优化),并在Go 1.21中,PGO实现生产可用,并增加了PGO驱动的去虚拟化(Devirtualization)。这表明Go官方对利用运行时信息提升性能的重视以及持续的投入。并且,通过用户的实际体验报告来看,PGO的确可以在一定程度上改善Go应用的性能,在Go 1.21及后续版本中,启用PGO 后,工作负载的性能常会有2%到7%的提升。

不过此前一直缺少来自大厂对PGO实践效果的声音,而Uber恰恰满足了Go社区的这个需求。

2. Uber的大规模PGO实践:自动化与挑战

面对数千个Go微服务,Uber在内部构建了一个持续优化的PGO框架

其流程大致如下:

  • 持续性能分析: 每日自动收集生产环境中多个服务实例的pprof CPU profiles。
  • 配置文件聚合: 将收集到的profiles进行合并,生成具有代表性的服务性能画像。
  • 服务注册: 通过配置系统,选择性地为特定服务开启PGO编译。
  • CI/CD 集成: 在持续集成环节,使用-pgo标志和生成的profile文件编译Go服务。
  • 部署与监控: 将PGO优化的二进制文件部署到生产环境,并通过监控仪表盘追踪性能变化。

然而,大规模推广PGO并非一帆风顺。Uber很快遇到了一个关键挑战:启用PGO后,部分服务的编译时间急剧增加,最高可达8倍!这严重影响了开发和部署效率。

通过深入分析,团队发现根源在于Go编译器在为每个包编译时,都需要重复读取和解析完整的pprof文件,这在高并发的构建系统中造成了巨大的I/O和CPU开销,占据了PGO编译流程中高达95%的时间。

如何解决这个问题呢?我们接着看Uber工程师的创新方案。

3. 破局:创新的Profile预处理工具

为了解决编译耗时的瓶颈,Uber与Google Go编译器团队合作,开发并向上游贡献了一个profile预处理工具(该功能已集成到Go 1.23)。

这个工具的核心思想是“一次解析,多次使用”。它能够独立运行,提前读取原始的pprof文件,并解析profile数据以提取函数调用关系和频率信息。关键信息被转换并缓存为一种紧凑的中间格式(WeightedCallGraph,或加权调用图),使得Go编译器可以直接读取这种轻量级的中间格式,无需再解析庞大的pprof文件,从而显著降低编译开销。

在Uber内部部署该预处理工具并每日更新预处理后的profile后,有效解决了PGO带来的编译时间增加问题,大部分服务的编译耗时恢复到了接近优化前的水平,为PGO的大规模应用铺平了道路。

既然问题解决了,那PGO优化带来的最终效果如何呢?下面就来揭晓答案。

4. PGO的性能影响:实证与观察

虽然在Uber复杂的生产环境中精确衡量PGO的独立影响(排除流量波动、自动伸缩、代码变更等因素)存在挑战,但他们的分析依然揭示了PGO的价值。他们分别观察了基准测试的结果以及生产环境的结果。

  • 合成基准测试

在流行的go-json库基准测试中,PGO带来了平均12% 的性能提升,部分微基准测试提升超过20%。观察发现,PGO显著降低了30%以上的iTLB misses,并能内联一些因体积过大而被默认启发式规则忽略的热点函数(如checkValid)。在tally指标库基准测试中,PGO也带来了平均10% 的性能提升,部分测试超过50%。

  • 生产环境观察

通过对比启用PGO前后7天的性能数据,Uber对其Top 6的Go服务进行了分析。结果显示,启用PGO后,这些服务的CPU核心分配数出现了可见的下降趋势。综合估算,PGO优化(主要是内联改进)在这些顶级服务中贡献了约4% 的性能增益,相当于节省了约24,000个CPU核心

此外,通过对比 PGO 前后的profile火焰图,可以确认PGO确实内联了之前未被内联的关键热点函数,验证了性能提升主要来源于PGO优化。

5. GOGC调优回顾:Uber的优化基因

值得一提的是,PGO并非Uber在Go性能优化上的首次大规模尝试。

多年前,他们通过名为GOGCTuner的内部工具,解决了Go GC(垃圾回收)在大量服务中CPU占用过高的问题。默认的GOGC=100策略对于内存使用模式多样且运行在有内存限制容器中的服务并非最优,容易导致GC过于频繁或存在OOM风险。

为此,Uber开发了GOGCTuner库,能够根据容器的cgroup内存限制动态调整GOGC值,例如设定一个内存使用上限百分比(如70%),以在保证内存安全的前提下尽可能减少GC次数,从而降低CPU开销。该工具巧妙地利用runtime.SetFinalizer实现了低开销的GC事件触发调整机制,最终为Uber节省了约70000个CPU核心。具体内容可以参见本文参考资料中的”How We Saved 70K Cores Across 30 Mission-Critical Services”一文。

从GOGC调优到PGO自动化,也体现了Uber在Go性能优化领域持续投入和系统化解决问题的工程文化。

6. 小结

Uber的实践清晰地表明,PGO是Go性能优化的一个强大武器,尤其对于CPU密集型或具有复杂调用关系的应用。虽然大规模应用PGO会遇到挑战(如编译时间),但通过工具创新(如Go 1.23集成的profile预处理功能)是完全可以克服的。

对于广大Go开发者而言,关注PGO显得尤为重要。随着Go版本的迭代,PGO的能力和易用性也在不断提升,了解并尝试在自己的项目中应用PGO,可能会带来意想不到的性能收益。

Go 1.23及以后版本集成的PGO预处理能力,大大降低了PGO的使用门槛,有效解决了编译耗时的主要痛点。同时,学习Uber系统化、数据驱动的性能优化方法论,从GC调优到PGO,能够帮助开发者持续挖掘性能潜力。

Go社区与像Uber这样的大规模实践者之间的良性互动(问题发现、解决方案到上游贡献)正在不断推动Go语言及其工具链走向成熟和高效。我们期待看到更多Go应用通过PGO等先进优化技术实现性能的新突破。

本文内容主要基于Uber Engineering Blog的两篇文章(见参考资料列表),特别感谢Uber工程师团队(包括前成员Jin Lin、Raj Barik等)以及Google Go编译器团队(Michael Pratt、Cherry Mui、Austin Clements等)在PGO领域的探索、实践和分享。

你对在项目中使用PGO有什么看法或疑问吗?欢迎留言讨论!

7. 参考资料


Gopher部落知识星球在2025年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。并且,2025年将在星球首发“Gopher的AI原生应用开发第一课”、“Go陷阱与缺陷”和“Go原理课”专栏!此外,我们还会加强星友之间的交流和互动。欢迎大家踊跃提问,分享心得,讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落,享受coding的快乐! 欢迎大家踊跃加入!

img{512x368}
img{512x368}

img{512x368}
img{512x368}

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格6$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻) – https://gopherdaily.tonybai.com

我的联系方式:

  • 微博(暂不可用):https://weibo.com/bigwhite20xx
  • 微博2:https://weibo.com/u/6484441286
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • Gopher Daily归档 – https://github.com/bigwhite/gopherdaily
  • Gopher Daily Feed订阅 – https://gopherdaily.tonybai.com/feed

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言进阶课 AI原生开发工作流实战 Go语言精进之路1 Go语言精进之路2 Go语言第一课 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com
这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats