其实从一开始了解到go的goroutine概念就应该想到,其实go应该就是在内核级线程的基础上作了一层逻辑上的虚拟线程(用户级线程)+ 线程调度系统,如此分析之后,goroutine也就再也不那么神秘了。golang
假如咱们有一段CPU密集型任务,咱们建立2000个gorountine是否真的能够将其性能提升2000倍,答案必然是不能,由于咱们只是进行了2000次的并发(concurrency),而并无真正作到并行(parallelism)。编程
并发其实所指的是咱们的程序执行逻辑,传统单线程应用的程序逻辑是顺序执行的,在任什么时候刻,程序只能处理同一个逻辑,而并发指的是,咱们同时执行多个独立的程序逻辑,若干个程序逻辑在执行时能够是同时进行的(但并不表明同时进行处理)。实际上,不论咱们并发多少个程序逻辑,若咱们仅仅将其运行在一个单核单线程的CPU上,都不能让你的程序在性能上有所提高,由于最终全部任务都排队等待CPU资源(时间片)。安全
而并行才能让咱们的程序真正的同时处理多个任务,但并行并非编程语言可以带咱们的特性,他须要硬件支持。上面说到单核CPU全部资源都要等待同一个CPU的资源,那么其实咱们只要将CPU增多就能真正的让咱们实现并行。咱们可使用多核CPU或用多台服务器组成服务集群,都可实现真正的并行,可以并行处理的任务数量也就是咱们的CPU数量。服务器
引用Rob Pikie大神在PPT《Concurrency is not Parallelism》中的一段总结,大意就是并发不一样于并行,但并发也许可让程序实现并行化。多线程
Concurrency vs. parallelism Concurrency is about dealing with lots of things at once. Parallelism is about doing lots of things at once. Not the same, but related. Concurrency is about structure, parallelism is about execution. Concurrency provides a way to structure a solution to solve a problem that may (but not necessarily) be parallelizable.
那么是否是说咱们在单核CPU的机器上使用编程语言所提供的多线程就没有意义了呢?并发
若是说咱们的程序属于CPU密集型,使用并发编程,可能确实没法提高咱们的程序性能,甚至可能由于大量计算资源花在了建立线程自己,致使程序性能进一步降低。编程语言
但不一样的是,若是说咱们的程序属于IO密集型,当你在进行程序压测的过程当中可能发现CPU占用率很低,但性能却到了瓶颈,缘由是程序将大量的时间花在了等待IO的过程当中,若是咱们能够在等待IO的时候继续执行其余的程序逻辑便可提升CPU利用率,从而提升咱们的程序性能,这时并发编程的好处就出来了,例如Python由于GIL的存在实际上并不能实现真正的并行,但他的多线程依旧在IO密集型的程序中依旧有种很重要的意义。ide
上面说到了使用多核CPU实现并行处理,使应用在多核cpu实现并行处理的方案主要是多进程与多线程两种方式,多进程模型相对简单,可是有着资源开销大及进程间通讯成本高的问题。多线程模型相对复杂,会有死锁,线程安全,模型复杂等问题,但却由于资源开销及易于管理等优势适用于对于性能要求较高的应用。函数
Golang采用的是多线程模型,更详细的说他是一个两级线程模型,但它对系统线程(内核级线程)进行了封装,暴露了一个轻量级的协程goroutine(用户级线程)供用户使用,而用户级线程到内核级线程的调度由golang的runtime负责,调度逻辑对外透明。性能
goroutine的优点在于上下文切换在彻底用户态进行,无需像线程同样频繁在用户态与内核态之间切换,节约了资源消耗。
同时,启动一个gorountine很是简单,并且写法很cool~
go function()
仅仅须要在调用函数时在前面加上关键字go便可建立一个goroutine并建立其上下文对象。
G(Goroutine) :咱们所说的协程,为用户级的轻量级线程,每一个Goroutine对象中的sched保存着其上下文信息
M(Machine) :对内核级线程的封装,数量对应真实的CPU数(真正干活的对象)
P(Processor) :即为G和M的调度对象,用来调度G和M之间的关联关系,其数量可经过GOMAXPROCS()来设置,默认为核心数
每一个Processor对象都拥有一个LRQ(Local Run Queue),未分配的Goroutine对象保存在GRQ(Global Run Queue )中,等待分配给某一个P的LRQ中,每一个LRQ里面包含若干个用户建立的Goroutine对象,同时Processor做为桥梁对Machine和Goroutine进行了解耦,也就是说Goroutine若是想要使用Machine须要绑定一个Processor才行,上图中共有两个M和两个P也就是说咱们能够同时并行处理两个goroutine。
这一篇主要讲解了一些并行与并发的区别Golang并发模型的优点,下一篇会详细说明GPM模型的调度策略。