《并发哲学:从编程入道到开悟升天》3.7 并发编程的模块、范式、设计
并发编程的模块、范式、设计
本章我们讲解了基于Golang的并发编程知识。
相比第一章和第二章,本章的理解门槛进一步提升,因为有越来越多的与代码相关的知识涌现出来。但对于渴望依托并发思想实际提升程序运转能力的人们来说,无疑是可喜的,因为我们用具象的手段,将并发思想融入到了具体程序中。
学习并发编程的编程语言选型
首先,我们介绍了云原生时代下首选的并发编程学习语言——Golang,得益于谷歌的品牌背书,Golang自诞生之时,就是一门现代编程语言,这不仅意味着多核、面向网络等设计因素被充分考量,切实方便程序员进行现代高级语言编程也成为了现代所有新生编程语言的使命。
从Golang的基本案例中,我们可以体会到,相似的写法在C语言、python、java里面都能或多或少的找到一点影子。在面向并发的原语抽象中,Golang是最为简单的,以发起并发任务为例,Golang做到了全部的关键字只有两个字母——go。
了解Golang语法的基础知识
对于许多java、python转来的开发者,学习Golang的基础知识至关重要,尽管相信各位读者已经在阅读本书之前了解了或多或少的Golang语法知识,但我们还是希望可以简单过一下本书提及的Golang基本知识,确保我们之后的学习路程中的关键知识点没有遗漏。通过顺带一提的方式,我们进入了Golang有关并发抽象原语的相关学习。
了解Golang关于并发原语的要素
通过精巧的案例赏析,我们了解了Golang关于并发原语的要素。在必读章节内,我们了解到,Golang关于并发的三大重要原语分别为:
- 并发任务启动:go
- 信息有序交互:channel
- 事件等待确认:select
同时,在可选章节内,我们也了解到,即使Golang的channel已经充分贯彻了CSP并发基本理论模型,Dijkstra的数据定向传送设计思想,但是为了更好的继承其他先前普遍流传的CSP内存访问同步原语,提供更多更加普适和易于理解的并发控制手段,Golang的sync库提供了进一步的抽象,形成了如下作用的其他并发原语:
- 任务下发计数:WaitGroup
- 锁与互斥锁:Mutex和RWMutex
- 事件交会标记:Cond
- 确保任务只执行一次的声明:Once
- 无边界资源池:Pool
希望你能够通过可选章节内上厕所、搬砖头、做菜、抢会议室和酒吧喝酒几个生动形象的小例子,来记忆住这些额外并发原语的基本用法和代码价值,同时体会背后蕴含的两大基本模型折射的人-物协调和人-人协调。
了解常见并发范式
在3.5节中,通过了解范式,我们应掌握基于各类并发原语形成的一些高级编码组织方法,通过这些方法构建出的代码区块,拥有职责明晰、功能确切的高级价值。这些基于范式构建的代码,可以在更加大型的系统内部进一步组织,从而创造出成倍的价值。我们了解了如下范式:
- 不可变约定:编码和设计级别解决资源冲突,从而构建并发安全
- 协程闭包:自我因果影响,限定资源作用域
- done通道:承载和协调特殊关闭信号量
- for-select:常见的构建条件阻塞-等待-循环再条件阻塞的方法论
- or-channel:规范的终止信号合并手段,可用于做到一人完成,任务停止
- chRange:安全的遍历通道方式,用于构建可控遍历通道
- tee-channel:数据和信号的三岔口,用于复制同请求到多个数据流
- bridge-channel:通道桥接器,实现多个通道的安全遍历和数据收集
- 规整化流水线:全程可控的任务有序数据流
如果把程序比作一个大工厂,那么整个程序的运转就好比不同地点的工人、领导利用不同工具,以秩序开展生产。细分成为点和流,范式对其中点和流的经验组织方式进行了标准化。可以说,这些范式的灵活运用,对于构建易于维护、稳定健壮、更优价值的应用程序具有重要意义,希望你能认真体会和学习。同时,字里行间我们也不忘穿插基于代码和日常生活中行为规范的映射。范式的应有之义就是:如果你想怎样,你应该这样做。
了解可伸缩并发设计
掌握了基础要素和行为规范,接下来我们继续了解了在可伸缩并发设计中需要考虑的常见问题,包括如下:
- 任务分配、规划和协调:任务的切分,应做到高内聚、低耦合。在多任务的组织中,对于重复、相似的任务,安排多人去分别做,在对响应要求高的任务中,安排多人同时做,谁先做完,以谁的结果为准。Golang对于这些与日常生活领导安排办事的经典抽象提供了完整的并发原语支持。
- 并发任务与速率限制:由于资源制约和安全性考量,我们需要引入并发限制。建立并发任务的标记映射,构建合适的令牌桶机制,来实现并发控制。
- 定位任务分配异常:通过合理有效的错误信息跟踪,至少应该实现包括①发生了什么②何时何处③有效的信息说明④如何获取更详细的错误信息在内的四点错误展示要素,这样才能更好的定位到任务分配异常。
- 监测、发现损失并定损与止损:错误定位是后知后觉的发现手段,程序运行时的自我调节修复也至关重要。通过心跳机制,我们可以更好的监测整个任务链路。通过构建以心跳为监控手段的协程自启动机制,则能够更好的止损。
- 超时和取消:尽管很多情况下安排的任务并没有发生意外,但是并不意味着等待是无休止的,这就意味着超时机制的引入。而超时暗含着隐式的取消,通过done通道和其他机制的配合,可以实现基本的取消。然而,对于取消带来的回滚等问题,则需要更多考量——代码设计上,我们通过划定最小原子操作来尽可能避免回滚;代码实现上,我们可以通过构建双向心跳和幂等下游信息传输等措施,减少回滚带来的负面影响。
在3.6节中,我们模拟了读者为真实厂长的血泪创业史,来说明具体并发编程中需要考量的并发设计因素。通过对并发设计的进一步探究,希望你能够构建应对更多场景、更加高效可靠的并发程序。
通过第一章并发思想起源探讨,第二章对理解方式的深入分析,再进入第三章编程能力学习的时候,我想即便在之前你对Golang相关并发知识有所掌握,想必也可以耳目一新,找到更多的内容。在下一章节,我们将再次深入到背后,介绍更多关于并发相关的知识,只不过这次,你能够以更加精准的代码工具来具象化的思考很多问题了。