你好,我是鸟窝。很高兴和你一起度过了一个多月的时间,到了和你说再见的时候了。
在过去的这些年里,我一直在研究Go并发编程,时间越久,越觉得,掌握Go并发原语是一件很有意思的事情。
很多刚开始学习并发原语的同学给我留言说:“使用Go写并发程序很容易啊,为啥要学这么多并发原语呢?”
如果你也有这样的疑问,我的答案就是在这节课的封面图中写的那句话:“并发原语,初识时简单,深交时复杂,熟识时又觉简单。”这是我的真实体会。
如果你处于刚开始接触并发原语的阶段,你可能会觉得:“这挺好理解的呀,我一看就会了。”但是随着学习的不断深入,你会看到各种复杂的用法,各种潜在的坑,这些东西打破了初印象,你会陷入到“千头万绪”的境地。只要你不畏困难,持续学习,最后你就可以轻松地使用这些并发原语了。如果说最初的“简单”是“初生牛犊不怕虎”的“简单”,那么“熟识”后的“简单”,就是“拨云见雾”的“简单”。这也是,我在这门课里想要带你达到的状态。
总之,使用Go写并发程序很容易,使用Go写好并发程序很不容易。
遗憾的是,很多人都没有意识并发编程的复杂性,甚至还没有意识到,并发编程错误带来的严重后果。所以,我想跟你分享关于并发编程Bug的两个小故事。
第一个故事,是我刚刚看到的澳大利亚交易所(ASX)的新系统在上线后崩溃的故事。
11月16 日中午,ASX发布声明说,当天将休市,会在次日的正常时间重新开放。官方给出的关闭原因是“局限于单个交易指令中交易多种证券(组合交易)的软件问题,导致了市场数据不准确。”
虽然我并没有看到这个Bug的细节,但是,从官方提供的关闭原因中,我们可以简单地推断出是“单个指令中交易多种证券的问题”,大概率是一个并发问题的Bug。虽然经过一天的排查和修复,第二天这个交易所就恢复上线了。但是,耽误一天的时间,损失也是非常大的。
类似的软件Bug,尤其是并发问题的Bug,即使经过很长时间的测试,也不一定能被触发和发现。可是一旦出现,就可能是一个一级的Bug。
如果看完这个故事,你还没有意识到并发编程的复杂性和并发问题的危害,我再给你讲一个故事。
1997年7月,NASA 的 Mars Pathfinder(火星探路者)在降落火星表面后不久,就因并发软件中的一个缺陷受到了威胁。这是在飞行前的测试中发现的,但因为它只发生在某些没有预料到的重载条件下,所以被给予了较低的优先级。
但是,飞船开始采集气象数据的时候,它所使用的 vxWorks 操作系统就出现了问题,不断地重启。这是经典的优先级反转的并发Bug。
幸好工程师上传了一小段 C 语言程序给飞船,在运行的时候,将优先级继承的互斥标志从 false 改成了 true,才成功地解决了这个Bug。
这次人为的忽视,险些酿成惨剧。所以,学好并发编程,是我们的重要责任。
那么,该怎么在编写Go程序时,避免并发编程的Bug呢?在开篇词里,我讲到了“两大主线”,现在学完了所有内容之后,你会发现,其实可以抽象成“三部曲”:
在前面的课程中,我讲的所有内容,都是为了帮助你轻松地完成这三个目标。在课程的最后,我还想再给你多交代几句。
学完这门课,并不代表你已经掌握了Go并发编程的知识。Go并发编程的知识广、内容深,现在你再回顾前面的知识,可能已经遗忘了一大半了。即使你现在记得很清楚,等过一段时间,再提到这些知识点,你也可能答不上来。
所以,学完这门课并不是一件一劳永逸的事情,你要在空闲的时候多复习下前面的内容。怎么复习呢?你可能也注意到了,每讲完一个并发原语,课程里都有一张知识导图,这些图既可以帮助你梳理知识主线,也可以帮助你高效地复习。
你可以对照着图中的核心要点,去回顾我们学习的重要内容,如果感觉有些地方比较陌生了,就及时回去复习下。另外,你也可以做一些摘录,并且写上你自己的收获和思考。学习过不等于能输出,你一定要记住这句话。
另外,这门课的核心是讲Go并发原语的知识,并没有涉及到Go并发模型和调度的事情。这不是说,我认为这部分内容不重要,而是很多大牛已经把这些内容写得很清楚、很明白了。如果你对这方面的知识还不太熟悉,可以搜索关键字“golang gpm schedule”,你会看到很多资料。你读几篇,就明白了。如果要推荐的话,我建议你重点读一读欧长坤的 《Go语言原本》的 并发调度,这一篇的逻辑非常顺畅,能看出非常多的经验。
当然,我还想再给你推荐一些补充资料,如果你还有余力,可以再扩展一下知识面。
首先是一本书,名字是“Concurrency in Go”。这是第一本全面介绍Go并发编程的图书。书中介绍了并发编程的背景知识、常见的原语和并发模式。我印象最深的,就是书里对Channel的介绍,比如Channel是粘合goroutine的胶水,而select是粘合Channel的胶水。这样形象的说法,可以帮助你快速地学到精髓。
除此之外,Go官方博客列出的一些技术分享,比如Go Concurrency Patterns、Advanced Go Concurrency Patterns,都是不错的阅读材料,我建议你好好读一读。
好了,关于结课后的学习方法,我就说到这里。在这节课的最后,我特别想再和你分享我自己的两个心得。
第一,开放的心态,可以拓展你的人生边界。
我始终认为,一个人衰老的标志,不是指他的容貌经历了太多岁月的刻画,而是他的内心封闭了,不再接收新的知识、新的事物。
在一些技术交流会上,我听到一些开发者说,Go并发编程很简单,有什么可学的?遇到这种不是技术讨论的话题,我一般只会说:“你说得对。”
我当然认同我们应该把核心精力用在眼下有价值的事情上,在自己擅长的领域里深耕,但是我更相信,开放心会让你的人生与众不同。如果你碰见了新技术的发展,即使不需要深入地学习,也要尽量花时间去了解一下,也许这些新的东西,就是你人生的转折点。
我之前就是一直使用Java、Scala,后来才开始了解Go,但是,很显然,Go给我的人生带来了不一样的东西。如果不是深入研究Go,我就没有机会开设这么一门课了。
第二,无数人想要你的注意力,但只有你能决定你把它放在哪里。
我们总说这个时代是信息爆炸的时代,其实,信息爆炸就意味着千万的信息发送者想要占用你的注意力。你一定要保持谨慎,不要毫无感知地把你的时间扔给无价值、无意义的信息。
如果说上一条是让你延伸注意力的触角,那么这一条,就是让你收缩注意力的触角,但这两者并不矛盾,因为侧重点不同。“延伸”还是“收缩”,取决于你自己想要拥有的人生的样子,只有你能决定。我能做的,就是提醒你,要开放,也要谨慎。
虽然很舍不得,但还是要跟你说再见了。在课程的最后,我给你准备一份结课问卷,希望你花1分钟时间,点击下面的图片填写一下。如果你的建议被采纳,我将会给你赠送一个护腕垫或者价值99元的课程阅码。期待你的畅所欲言。
评论