《并发哲学:从编程入道到开悟升天》3.1 利用Golang讲解并发编程
利用Golang讲解并发编程
本章学习,适合具有至少一门编程语言基础的同学进行学习。如您不是计算机专业相关人员,跳过本章,对并发哲学的相关探讨影响也是微乎其微的,特此说明。
从本章开始,我们将正式开始把编程实践引入到并发哲学的相关探讨。从前两章走来,你已经了解了并发的哲学思想起源,和两种我们极力推荐用于理解并发的方式,我们再一次总结如下:
- 无法并行执行任务的个体需要并行执行任务,必须借助其他个体来实现。宏观来看,并发探讨的是在该场景下一系列的思想、建模、实践工作。
- 基于历史,投掷者模型和包工头模型很好的总结了人类发展进化中***性的两大里程碑:1. 理解并运用投掷能力实现借助自然规律,高效率协调人-物关系 2. 高效分工协调与合作,造就的以人为核心,人-人协同的社会化生产。 由于人-物、人-人关系是以人为核心社会的全部,因而这两大模型值得推崇。
回顾编程这一人类行为,本质是借助计算机和相关现代工具,利用条理性的记录,对运作过程进行预见性的组织和安排,也是人类利用高级工具的一种方式,也是人机交互的一种途径,核心目的还是在于利用高级工具,实现更大价值,解决实际问题。
那么,开始并发编程的相关学习,对编程语言的选型,我们需要关心哪些问题呢?在我们看来,需要关心的问题如下:
- 编程语言是否标准。包括体现在该语言是否简介清晰,是否结构明了,是否在语法风格上有较为统一的标准和规范。毕竟,明确的语义、清晰的结构、规范的风格,更有助于知识的标准化沉淀和流传。
- 编程语言是否能对并发概念进行良好抽象。包括使用并发能力是否方便,并发相关能力关心的要素是否齐全,毕竟只有良好抽象,才有助于人们更好的建模,更好的将并发设计进行进一步探讨,提升处理问题的思考效率。
- 编程语言是否针对客观并行要素做有利优化。仅仅是理解上的语法糖,无法更好的在实现最终“价值的提升”上有更多建树,一个良好的用于实践并发编程的语言,应该需要在底层针对支持客观并行元素做特别优化,为价值实际提升提供可靠基础。
- 编程语言生态是否良好。生态十分重要,并发编程学习不是一朝一夕,所学所得也需要具体工程实践才能创造真正生产价值。如果通过该编程语言的学习,可以在较广泛方面运用学到的知识,而且不但有良好开发者资源做支持,还有大型流行工程项目做衬托,甚至有可靠行业品牌进行背书,无疑能够对学习成果的保值提供可靠担保。
这样看来,Golang作为并发编程学习的首选语言,可以说是十分合适的。
可靠品牌背书,流行火热项目内常见其身影
Golang(又称Go)是谷歌2009发布的第二款开源编程语言,谷歌作为软件巨头,其品牌背书作用不言而喻。
在云原生时代流行的项目内,尤其是Devops工具链,我们也可以常见到Go的身影。下面所有的框架和程序,均是使用Go进行编写,可供各位读者参考:
- WEB及微服务基本编程框架:beego、gin、HUGO,广泛运用于各大互联网企业内。
- 容器和云原生:docker、k8s,两大容器化及编排的事实标准,云原生时代的程序员应该都耳熟能详。
- 键值与时序数据库:etcd、influxdb、consul,广泛用于监控数据存储、服务发现、配置存储等领域
- 监控和可视化:Prometheus、grafana、open-falcon,这几个都是近几年业内运维监控的事实标准和样例,也不赘述。
我们可以看到,几乎在所有云原生、监控及配套存储、可视化的当代标准内,都可以看见Go的身影。仅从现象上来说,Go已经成为了一门生态颇为繁荣的语言。这些当代标准项目全部用Go语言构建的背后,代表着Go语言至少在Web服务、容器编排、高效存储、分布式、数据处理等方面有者标准范式,或者是解决方案模板,可以为后来的开发者提供卓有成效的借鉴。
可以说,打入当下的火热Devops技术链,Go语言成为了必修课,重要性不言而喻。
良好编程规范,极简并发抽象
Go本身具有严格的语法控制,但同时又借助简洁表示的机制,使得代码之间空格、代码行与行之间的展示变得额外规整,看一个如下的例子:
if err!=nil { return err }
可以看到,以条件判断语句if为例,条件的前后无需括号包裹,通过空格隔开,就可以同时形成面对语言的语义和面对编程者的语义,编程过程中更加简洁优雅。行与行之间无需分号,仅仅依靠换行就可以取得良好的展示效果。同时面向机器和编程者的友好编程书写语法,让人们在使用Golang编程的过程中,也可以轻松和愉快。
而对于并发的抽象,Go可以说正因此而生。我们简单体会一下下列场景的实现:
- 将一个函数A作为并发任务运行
如果是用java实现,我们一般会使用多线程,大概的实现如下:
首先我们需要创造一个重写了run方法,并继承了Thread的类
public class TestClass extends Thread { // 通过构造方法给线程名字赋值 public TestClass(String name) { super(name);// 给线程名字赋值 } // 需要重写run方法 @Override public void run() { System.out.println("程序运行"); } }
然后在需要调用该实例化对象方法的时候,使用start:
public class MainClass { public static void main(String[] args) { //实例化站台对象,并为每一个站台取名字 TestClass test1=new Station("A对象"); // 让每一个站台对象各自开始工作 test1.start(); } }
然而,如果是利用Go实现,那么只需要如下这样:
go A()
Go对于并发编程的抽象到了极致,一切的标记和初始化,都浓缩到了Go语言的名称作为的关键字“go”内部。基于如此简洁和强大的抽象,我们可以将精力投入到更加高层的思考活动中,去更好的进一步思考我们程序的建模,以及如何更好的通过编程解决我们的问题。
这样干练的抽象方式,用投掷者模型来看,就好比是丢出去石头一样简洁,正如go英文名称的含义:“走你!”一样。
高效执行效率,针对多核优化
javascript使用promise等机制,同样可以实现异步的编程,将任务标记为“稍后执行”。但可悲的是,受限于历史遗留问题,直至今日,包括javascript在内的一系列语言,都只能受限于单核性能。通过之前的学习可以了解,只要并行的实体需求没有得到满足,并发的效率是无法提升的。这也就意味着,在除去网络请求等依托其他体系完成的任务,js只能将任务标记为“稍后执行”,但不会有其他的人来帮助这个发配了任务的人执行需求,只有这个发配任务的人自己,才可以执行。
好在,java、python、C等一系列语言,可以通过引入必要语法元素来开启多核的支持,让那些发配出去的任务,有其他的物理核心可以参与到执行的过程中,切实为运行贡献一份力量,提升多核并发体系内的效率。不过,美中不足的是,这些特性都是在这些语言诞生后,逐步加入到其中的,犹如一个个补丁。究其原因,还是在于这些语言过于古老,他们诞生的那个时代,CPU多核的概念可能才刚刚萌芽。
Go原生对于多核做了优化。Go诞生于2009年,计算机的各项能力已经有了质的飞跃。作为一款基于C/C++打造的更加良好抽象与内存安全的语言,为进一步提升效率,在Go语言诞生之初,多核的有效利用就在设计考虑的范围之内。
不但对并发有良好抽象,写出来的并发代码,也一定要在支持多个小任务切实同时运行的计算机上,这样的并发才是真正提升了整个系统的价值。
或许现在所言还略有抽象,但希望你能明白,Go自身所具有的许多其他编程语言望尘莫及的闪光点,综合来看,Go是用于学习和实践并发编程的首选语言。
下一小节,我们将带领你走进以Go语言为核心视角的并发编程学习之旅。