关于go并发,作者之一Rob Pike有一个演讲:Concurrency is not Parallelism 即并发并非并行,这个非常基础性的概念有助于我们理解开发中的各种并发模式。
简单的讲,并行指多件事情可以同时进行或执行
,而并发则指多件事情“同时发生”
这里的同时发生打上了双引号表示其并非真正的在同一时刻发生,而是由于人感知的速度远小于计算机处理的速度,让人感觉多个事件是同时在进行和发生。但是这并非同时在执行。故并发有时候更像是为了达到并行同样的效果而采取的一种实现solution.
举一个现实中的例子,比如超市的收银台,如果要实现两个顾客同时结算,则必须需要至少两个收银台才能真正的执行同时收银操作,这就是并行。这对顾客来说当然是最快速的,都不用排队每个人都是优先用户。但收银台有限,必须提高单个收银台的效率,比如我们不用现金支付都采用扫码支付,又或者无人超市的过一遍自动结算。如果够快,那么收银台A依次处理两位顾客a1和a2和收银台B处理的顾客b1后出现在超市门口的速度几乎一样,对于外人来说,我们可以看到a1,a2,b1是几乎在同时出现在了超市出口,这就是并发。
在编程中经典的并发模式则是:多进程,多线程。由于cpu的速度够快,以至于在多个进程线程的切换中,基本无感知。但是随着进程和线程数的增多,资源占用和调度问题就会反向影响到性能。
go并发的实现方式,Goroutine,宣传非进程非线程,暂且称为go协程。一种比线程更轻量级的执行单元。
go的并发模型组成:G-P-M,这里先直接给出定义: G:Goroutine,即每次使用关键字go执行的代码 P:Procecessor,“处理器”,goroutine“执行”者,每个P后面都有一个goroutine队列,且P的个数等于GOMAXPROCS M:Machine thread,这个指实际线程,每一个P必须在一个M上运行
由此结构可以看出,go的并发调度其是在每一个线程上实现的P再去调度各个goroutine,此处每个P的goroutine队列即类似于“线程池”,简单讲就是在应用程序层本身做了一层调度封装! 实现代码段级别的最小执行单元并发及调度,以实现G:P:M:N的映射!显然用户态应用程序内的调度相比于内核系统调用实现切换廉价的多,对于内核线程而言是透明的,和执行普通的多线程程序并无差异。从某种程度上来讲,唤作”协程“,可理解为,线程/进程 协助调度程序。