评论:为什么你应该学 Go ?

这篇评论是我 ARTS 打卡中 Review 的部分,也就是阅读一篇英语(技术)文章,然后评论。

第一次做,也不知道做得对不对。不管,先实践,慢慢就会好的了。

平时太过于依赖翻译,只有极少数觉得翻译质量不好,乃至内容存疑,才会主动去翻英语资料。

所以当第一次为了打卡 无目标地主动 找英文材料看,突然不知道从哪里找起。翻了半天,大多是社交网络的碎片内容。眼看时间浪费了不少,先随便找了一篇,正好我最近也想写一下学 Go 的原因。

《Why should you learn go?》,文章地址:https://medium.com/@kevalpatel2106/why-should-you-learn-go-f607681fad65 (17 年 1 月的文章,有点旧。特别提醒,Medium 为 推家 旗下网站,访问需工具。)

如题,作者罗列了推荐 Go 的理由。我先简单总结作者观点(只是用引用格式区分,并非原文),再提出我的看法。

硬件限制

摩尔定律正在失效

过去十几年,计算机(单核)算力没有明显的变化。

随着在微观尺度上量子效应越发明显,堆砌晶体管数量也变得越来越难,越来越不经济。现在厂商只能增加内核数量和增大缓存。但这些办法也有其限制,很快就无法继续。

同意。我们认为开发者的时间比较宝贵,以及我们渴望更酷炫的效果,结果就是硬件进步获得的性能,都在软件层面被挥霍掉。我们愿意花费大量的算力,只是为了提升一点点人工的效率。过去这么多年,摩尔定律虽然不精确,也基本预言了性能提升的趋势。软件的最终运行速度,不仅没有怎么提升,甚至有些还变慢了。

这种『挥霍』多数情况下,其实是合理 的。假定 10 年里算力提升了 50 倍,面对一个要 80 工时开发的,10 年前运行时间要 1 秒的程序,有两个选择:

  • 维持 10 年前的开发方式,开发工时和运行效率都不变。这意味着算力提升后,程序运行时间变成 1/50,也就是 20 ms。获得了 980 ms 的提升。
  • 为了减轻开发负担,引入更多中间层,屏蔽更多细节。一般来说,我们不能忍受变得更慢,理想情况下,运行效率的降低大致上更好跟算力的提升打平,也就是运行时间在 10 年后还是 1s,以此换得开发时间减半。开发者省下了 40 工时。

例子非常粗糙,现实世界比这个复杂得多,但勉强能说明问题:50 倍 和 2 倍,看似前者更重要。可现实中我们比较的是差值。980 ms 运行速度提升,没有人在意;而 40 工时的提速,实际上重要的多。至于这 40 工时再被不确定的需求浪费掉,就是另一个故事了。

摩尔定律有效时,『挥霍』是理性的选择。不过,随着大规模分布式系统的普及,以及摩尔定律逐渐失效,在处理器有基础突破之前(超导?量子?),运行效率应该被重新重视起来。

Go 有协程

  • 轻量用户级协程,2KB 低开销,动态增长栈,MPG 调度模型 …… 轻易开到百万协程。对比之下,Java 线程开销 1MB 起。
  • CSP (Communicating Sequential Process,通信顺序进程)并发模型,可以大幅降低正确并发代码的心智负担。

总的来说,就是 09 年诞生的 Go,比这些上个世纪诞生的老前辈,更原生地支持 并发 和 并行。

用作者话说,强大如 Java,C/C++;代码直白优雅如 Erlang。

作者指出在摩尔定律失效的年代,靠增加 CPU 核心来提高算力。相应地,程序需要良好的并发,乃至部署分布式的系统(原文用的微服务)来更好地利用这些算力。

但随着了解深入,作为 Go 吹的我也必须指出两点:

  • Java 通过第三方库也引入了协程 和 CSP。虽然使用不如原生的直接,但是结合 Java 已有的生态,还是增强了 Java 在并发方面的能力,使得 协程 + CSP 不再是 Go 的专属。
  • CSP 的底层依然是靠 锁 实现的,只是通过封装向开发者屏蔽了复杂性。在大多数场景,性能不差,同时大大降低了心智负担。但是极端情况下,还是自己控制锁的粒度才能最大限度发挥性能,这时 Go 并没有明显的优势。

Go 直接运行在硬件上

其实就两点

  • Go 是编译语言
  • Go 没有虚拟机

作者就是想说,Go 没有虚拟机,运行接近 C/C++ 的速度,但又不用像 C/C++ 那样自己管理内存。

这里要提点反对意见了。早些年我也想当然地认为,Go 接近 C/C++ ,Go 肯定比 Java 快。

现在我要说,这是 分场合的 。Java 凭借多年深厚的积累,特别是在不同场景下的 JIT 或 AOT 优化,有些情况就是比年纪尚轻的 Go 快。当然,发生在特定场景,在 Java 可以优化,而 Go 还没有或者基于某些设计不能进行优化的时候。更多情况下,Go 比 Java 快一点,或者差不多。懒得研究和稀泥说法是,它们都在比 C/C++ 略慢的第二梯队,比多数高级语言要快。但有一点是确定的,不能闭着眼睛说 Go 没有虚拟机就一定比有虚拟机的 Java 快

编译语言、没有虚拟机真正的优势在于,无依赖地跨平台发布。实际上,通过一些技巧,还能达到单文件发布。做过运维搞过批量部署的同学,会知道这是多么宝贵的特性。

Go 容易维护

Go 非常克制地保持了一个简洁和清晰的语法。

它拒绝了很多现代高级语言会有的特性,来避免副作用:

  • 继承
  • 构造函数
  • 注解
  • 泛型
  • 异常处理

它宁可让你多写两三行代码,也要保持代码的简洁明了和运行高效。

另外,Go 语法非常稳定,保持了很好的向后兼容。(向后指 backward,跟中文的语义理解上相反,其实指新版本兼容老版本,新环境能跑老代码)

这确实是值得称道的点。Go 核心团队以他们多年的经验,精心挑选了核心的特性,然后努力避免不必要的特性让语言变得臃肿。

但是,这往往也是一个被吹捧过度的点。例如缺乏泛型 是 Go 一直被诟病的。

缺乏泛型,让开发者不得不在 数据结构部分 充斥复制粘贴大量依赖代码生成器 之间做选择。

这就是语言表达力的问题。冗余代码就是会带来管理负担,代码生成器就是会引入额外依赖。

官方也没说过不需要泛型。只是说泛型相对不急,还没找到更好的实现方案,团队先把时间花在优化性能上。

一旦说了 Yes,之后就必须一直 Yes。现在说 No,以后还有机会说 Yes。(大意复述)

这才是核心团队的意思。泛型的草案已经讨论有年头了,社区的呼声也非常高。期待 Go 泛型的到来。

无论如何,足够精简的特性,对于 编译速度、运行速度 还有 开发者的心智负担,都很重要。也正是凭借这些方面的优势,让 Go 在各个方面都能做到接近第一梯队,然后整体下来一看,综合很强。

背靠 Google

以及很多大公司在用。

严格来说,这是生态角度。生态的几个指标:大厂支持,杀手案例,活跃社区,企业框架。

但是文章作者角度刁钻地说出了一个算技术方面的理由:

Google 见过大场面,Google 有世界最大规模的云设施之一,由它设计的语言一定会把它遇到的问题考虑进去,做到可扩展和高效。

呃,G 厂厉害也不是这样吹的。

结论

最后的结论还是『虽然我考试每科都是老二,但是总分高啊』。

运行速度不如 C/C++ ,但是开发效率和心智负担妥妥碾压。C/C++ 历史包袱重,对新手意味着学习曲线更陡、坑更多,对团队意味着管理难度高。对于离得硬件和性能稍微远一些的开发,这些代价可能不值得。

表达力、开发自由度不如 JavaScript 和 Python,但是静态安全性和速度又是遥遥领先。

所以 Go 就是很适合作为 CLI 工具、web 服务(特别是云原生的微服务)的开发语言。

因为优秀的类库还需要积累,又缺乏企业级的开发框架,距离 Java 还是有距离。但是发展到今天:

  • 大厂支持一开始就有,含着金钥匙诞生。
  • 杀手级案例,最早是 Docker 和 K8s,后面越来越多云生态的组件加入。
  • 社区人气是够的,其中中国开发者又是最捧场的。第三方库勉强够用,但是不足够好。特别是包管理转向 module 后很多包遗留了兼容问题。
  • 最后只是缺足够强大全面的,可以对标 spring 的开发框架。

学 Go 肯定是值得的。老手可能花一个小时就能大概上手。当前 Go 已经可以用于生产环境,用来搭建运维工具箱,或者实现一个服务。它就好像是专门为 分布式 和 云 准备的。但如果整个技术栈完全用 Go,生态还不如 Java 完善,可能还要自己踩一些坑。

必须承认,在强大全面的 Java 面前,Go 还是个弟弟。但奔 3 的 Java 已经开始有点油腻,才 10 岁的 Go 正年轻。


知识共享 “署名-非商业性使用-相同方式共享” 4.0 (CC BY-NC-SA 4.0)”许可协议
本文为本人原创,采用知识共享 “署名-非商业性使用-相同方式共享” 4.0 (CC BY-NC-SA 4.0)”许可协议进行许可。
本作品可自由复制、传播及基于本作品进行演绎创作。如有以上需要,请留言告知,在文章开头明显位置加上署名(Jayce Chant)、原链接及许可协议信息,并明确指出修改(如有),不得用于商业用途。谢谢合作。
请点击查看协议的中文摘要。