1. 进程

通俗的讲,应用程序运行起来就是进程,一个应用程序一般对应一个进程(也可多个);

每个进程都有自己的独立内存空间,拥有自己独立的地址空间、独立的堆和栈,既不共享堆,亦不共享栈;

进程由操作系统调度 ,操作系统会以进程为单位,分配系统资源(CPU时间片、内存等资源),进程是资源分配的最小单位。

2. 线程

一个进程一般有一个主线程,还有若干个辅助线程,线程之间是平行运行的;

线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是这样的),是操作系统调度(CPU调度)执行的最小单位。

3. 协程 

在线程里面可以开启协程,一个线程也可以拥有多个协程,协程的调度完全由程序员在代码里控制。协程和线程一样共享堆,不共享栈,协程就像轻量级的线程,在切换开销方面,协程远比线程小。

协程与线程主要区别是它将不再被操作系统内核调度,而是交给了程序自己,这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源,而线程是将自己交给内核调度。

4. goroutine

协程和golang中的协程(goruntine)是不一样的,Go 协程通过通道来通信而协程通过让出和恢复操作来通信;而且Go 协程比协程更强大。因为Golang 在 runtime、系统调用等多方面对 goroutine 调度进行了封装和处理,也就是Golang 有自己的调度器,工作方式基本上是协作式,而不是抢占式,但也不是完全的协作式调度,例如在系统调用的函数入口处会有抢占。当遇到长时间执行或者进行系统调用时,会主动把当前 goroutine 的CPU (P) 转让出去,让其他 goroutine 能被调度并执行,也就是我们为什么说 Golang 从语言层面支持了协程。简单的说就是golang自己实现了协程并叫做goruntine

goroutine(运行时)会在逻辑处理器上调度这些goroutine来运行,一个逻辑处理器绑定一个操作系统线程(指的是操作系统线程,即内核线程)。

全局运行队列调度器逻辑处理器本地运行队列逻辑处理器

  golang中设置逻辑处理器个数也非常简单,在程序开头使用runtime.GOMAXPROCS(逻辑CPU数量)即可,一般情况下,可以使用 runtime.NumCPU() 查询 CPU 数量,并使用runtime.GOMAXPROCS() 函数进行设置,当参数小于 1 时使用默认值。

对于逻辑处理器的个数,不是越多越好,要根据电脑的实际物理核数,Go 1.5 版本之前,默认使用的是单核心执行。从 Go 1.5 版本开始,默认执runtime.GOMAXPROCS(runtime.NumCPU()),最大效率地利用 CPU。

runtime.NumCPU()默认物理CPU数,

 

go语言中并发指的是让某个函数独立于其他函数运行的能力。