简介

简单介绍自己对并发编程模式的一些理解。

并发与并行

并发是指多个程序在一段时间内同时运行,而并行是指多个程序在某一时刻同时运行。所以并行也可以看做并行的特殊实例。并行也只能发生于多核计算机或者分布式系统中,试想,如果单台机器只有cpu只有单核,如何同一时刻运行多个程序呢? 接下来,总结下常见的并发编程模式。

多进程

进程是Unix衍生操作系统的根本,因为所有的代码都是在进程中执行的。也可以说一个程序的执行称为一个进程。 一个进程可以使用系统调用fork创建若干个新的进程,也称为子进程,因此,这个进程就是新创建进程的父进程。每个子进程都是父进程的一个副本,每一个副本都是独立的,也就是说,在fork调用之前都会被复制到各个子进程副本内,而副本内的操作对其兄弟进程和父进程是不可见的。这也就是多进程的进程隔离性,正是因其隔离性,可以尽量减少线程加锁/解锁的影响,极大提高性能。但是多进程之间通信比较复杂,需要利用管道,信号,消息队列等进行通信,并且调度开销比较大。

多线程

线程其实就是进程的一个控制流,每个进程都至少包含一个线程,这个线程也被称为主线程。一个进程内的所有线程是共享资源的,创建线程的代价比进程要小很多,apache使用的便是多线程并发处理。由于资源是共享的,所以不可避免的带来加锁解锁的复杂度,业务逻辑代码也因此变得复杂,同时,加锁解锁是非常消耗资源的。

协程

协程,也称用户态线程,线程的调度不经过系统内核,减少了大量的IO操作,所以性能很高。协程一般都是由语言层面进行支持,比如swoole支持协程。其原理就是多个用户线程和一个内核线程进行绑定,通过yeild进行切换上下文。协程的缺点就是如果某段程序堵塞,其他代码也就得不到执行。另外,由于协程都是语言第三方库进行实现的,在兼容性上稍弱,稳定性不高。

Go程

GO语言的Goroutine,它是结合线程和协程的产物。简单来说,就是多个Go程绑定多个线程,也称为两极态线程,内部其实很复杂,GO程逻辑关联对应多个P而每个个P又唯一关联一个线程,通过调度器来切换执行GO程。GO程是通过chanel通信的,chanel类似于消息队列,保证了并发的安全性。GO语言直接从语言层面对类似于协程的支持进行并发编程。

异步回调

典型的node语言,通过单线程异步事件回调无阻塞,本质就是不断在事件队列中添加事件,不断循环这个事件队列进行事件处理,性能非常高。但是缺点是,如果某个事件堵塞掉了,整个程序就完了,因为它是单线程的。还有就是回调编程不断的callback,嵌套层级过深(可以利用promise进行流程控制减少回调嵌套)。还有一点就是node程序受制于V8的效能。

待续···