进程&&线程&&协程

"三程":

  • 进程:程序的一次运行,资源分配(除CPU)的基本单位;
  • 线程:CPU调度的基本单位;
  • 协程:一种用户态、轻量级的线程;

用户态线程:

  • 内核看不到,不知道用户线程的存在,内核调度时,仍然以该进程为单位进行调度;
  • 用户级线程内核的切换由用户态程序自己控制内核切换(通过系统调用来获得内核提供的服务),不需要内核干涉,少了进出内核态的消耗,但不能很好的利用多核Cpu。
  • 任意时刻,每个进程只能够有一个用户线程在运行,尽管它是多线程的,这就不利于多核CPU的使用了;

协程就是一种用户态线程;

优点:线程的切换无需陷入内核,所以切换开销小,速度非常快;

缺点:同一个进程中同时只有一个线程在运行,一个线程的阻塞将导致整个进程的阻塞;

核心态线程:

  • 由内核进行管理,线程切换将会消耗较多资源。对于多核CPU,可进行多线程并行运行;
  • 内核能够感知到线程的存在,CPU调度时,是以线程为单位进行调度;

优点:可以多线程并行运行;

缺点:线程切换时,比较消耗资源。因为需要保存上下文,核心态和用户态的切换

两个切换的对比:

  • 用户线程切换:只设计基本的CPU上下文切换。切换是完全在用户态中进行的;
  • 内核线程的切换:也有上下文切换,且保存的东西更多一点。并且线程的调度只有内核才能完成,这就涉及到了用户态和核心态的切换,这才是最主要的开销;(进程的切换也要陷入内核)

内核线程和用户线程的联系

  • 一对一模型:充分利用了多核系统的优势但是上下文切换非常慢,因为每一次调度都会在用户态和内核态之间切换。POSIX线程模型(pthread)就是这么做的。
  • 多对一模型:多个用户空间线程在1个内核空间线程上运行。 优势是上下文切换非常快,因为只有一个内核线程嘛,用户线程切换时,内核的这个线程是不用动的。也就意味着没有了核心态和用户态的切换,以及内核线程的上下文保存。
  • 多对多模型:效率虽高,但是管理复杂;

Golang的Goroutine调度模型

goroutine就是协程,完全运行在用户态中,借鉴了N:M模型;

1、GMP模型

goroutineMachineLogical Processorruntime.GOMAXPROCS (numLogicalProcessors)

三者关系:

LRQ(Local Run Queue)GRQ(Global Run Queue)

2、go func()执行流程

全局G个数/P个数一次性转移一半
runtime.GOMAXPROCSN:M模型runtimeruntime.GOMAXPROCSruntime/debug.SeMaxThreadsSetMaxThreadsgoroutinegoroutine