进程,线程和协程

1,任务调度

要理解进程和线程,必需要先了解一下操做系统的一些相关概念。大部分操做系统(如Windows、Linux)的任务调度是采用时间片轮转的抢占式调度方式,也就是说一个任务执行一小段时间后强制暂停去执行下一个任务,每一个任务轮流执行。任务执行的一小段时间叫作时间片,任务正在执行时的状态叫运行状态,任务执行一段时间后强制暂停去执行下一个任务,被暂停的任务就处于就绪状态等待下一个属于它的时间片的到来。这样每一个任务都能获得执行,因为CPU的执行效率很是高,时间片很是短,在各个任务之间快速地切换,给人的感受就是多个任务在“同时进行”,这也就是咱们所说的并发(别以为并发有多高深,它的实现很复杂,但它的概念很简单,就是一句话:多个任务同时执行)。多任务运行过程的示意图以下:
 程序员

操做系统中的任务调度数据库

2,进程

咱们都知道计算机的核心是CPU,它承担了全部的计算任务;而操做系统是计算机的管理者,它负责任务的调度、资源的分配和管理,统领整个计算机硬件;应用程序侧是具备某种功能的程序,程序是运行于操做系统之上的。多线程

进程是一个具备必定独立功能的程序在一个数据集上的一次动态执行的过程,是应用程序运行的载体,操做系统会以进程为单位,分配系统资源(CPU时间片、内存等资源),进程是资源分配的最小单位进程通常由程序、数据集合和进程控制块三部分组成。并发

  • 程序用于描述进程要完成的功能,是控制进程执行的指令集;
  • 数据集合是程序在执行时所须要的数据和工做区;
  • 程序控制块(Program Control Block,简称PCB),包含进程的描述信息和控制信息,是进程存在的惟一标志。

进程具备的特征:异步

  • 动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生,动态消亡的;
  • 并发性:任何进程均可以同其余进程一块儿并发执行;
  • 独立性:进程是系统进行资源分配和调度的一个独立单位;
  • 结构性:进程由程序、数据和进程控制块三部分组成。

【进程间通讯(IPC)】性能

  • 管道(Pipe)、命名管道(FIFO)、消息队列(Message Queue) 、信号量(Semaphore) 、共享内存(Shared Memory);套接字(Socket)。

3,线程

早期的操做系统中并无线程的概念,进程是能拥有资源和独立运行的最小单位,也是程序执行的最小单位。任务调度采用的是时间片轮转的抢占式调度方式,而进程是任务调度的最小单位,每一个进程有各自独立的一块内存,使得各个进程之间内存地址相互隔离。至关于一个进程里只有一个线程,进程自己就是线程。因此线程有时被称为轻量级进程(Lightweight Process,LWP)spa

​​

早期的操做系统只有进程,没有线程操作系统

 

后来,随着计算机的发展,对CPU的要求愈来愈高,进程之间的切换开销较大,已经没法知足愈来愈复杂的程序的要求了。因而就抽象出一个更小的概念——线程线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。线程

一个进程能够有一个或多个线程,各个线程之间共享程序的内存空间 (也就是所在进程的内存空间) 。3d

一个标准的线程由线程ID、当前指令指针(PC)、寄存器和堆栈组成。而进程由内存空间(代码、数据、进程空间、打开的文件)和一个或多个线程组成。

线程的出现,使得一个进程能够有多个线程

单线程与多线程的关系

 

用户线程和内核线程的关系模型

线程又被称为 用户线程(用户态),每个用户线程都要有一个 内核线程(内核态) 在支持。用户线程 与 内核线程的对应关系有三种模型:一对一模型、多对一模型、多对多模型,在这以4个内核线程、3个用户线程为例对三种模型进行说明:

一对一模型

对于一对一模型来讲,一个用户线程就惟一地对应一个内核线程(反过来不必定成立,一个内核线程不必定有对应的用户线程)。这样,若是CPU没有采用超线程技术(如四核四线程的计算机),一个用户线程就惟一地映射到一个物理CPU的线程,线程之间的并发是真正的并发。一对一模型使用户线程具备与内核线程同样的优势,一个线程因某种缘由阻塞时其余线程的执行不受影响;此处,一对一模型也可让多线程程序在多处理器的系统上有更好的表现。

但一对一模型也有两个缺点:1. 许多操做系统限制了内核线程的数量,所以一对一模型会使用户线程的数量受到限制;2. 许多操做系统内核线程调度时,上下文切换的开销较大,致使用户线程的执行效率降低。

一对一模型

多对一模型

多对一模型将多个用户线程映射到一个内核线程上,线程之间的切换由用户态的代码来进行,所以相对一对一模型,多对一模型的线程切换速度要快许多;此外,多对一模型对用户线程的数量几乎无限制。但多对一模型也有两个缺点:1. 若是其中一个用户线程阻塞,那么其它全部线程都将没法执行,由于此时内核线程也随之阻塞了;2. 在多处理器系统上,处理器数量的增长对多对一模型的线程性能不会有明显的增长,由于全部的用户线程都映射到一个处理器上了。

多对一模型

多对多模型

多对多模型结合了一对一模型和多对一模型的优势,将多个用户线程映射到多个内核线程上。多对多模型的优势有:1. 一个用户线程的阻塞不会致使全部线程的阻塞,由于此时还有别的内核线程被调度来执行;2. 多对多模型对用户线程的数量没有限制;3. 在多处理器的操做系统中,多对多模型的线程也能获得必定的性能提高,但提高的幅度不如一对一模型的高。在如今流行的操做系统中,大都采用多对多的模型。

多对多模型

4,进程与线程的区别

前面讲了进程与线程,但可能你还以为迷糊,感受他们很相似。的确,进程与线程有着千丝万缕的关系,下面就让咱们一块儿来理一理:

4.1 进程是操做系统分配资源的最小单位,线程是程序执行的最小单位;

4.2 一个进程由一个或多个线程组成,线程是一个进程中代码的不一样执行路线;

4.3 进程之间相互独立,但同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号),某进程内的线程在其它进程不可见;

4.4 调度和切换:线程上下文切换比进程上下文切换要快得多。

进程与线程的资源共享关系

 

5,协程

协程,英文Coroutines,是一种基于线程,但又比线程更加轻量级的存在,这种由程序员本身写程序来管理的轻量级线程叫作『用户空间线程』,具备对内核来讲不可见的特性。

由于是自主开辟的异步任务,因此不少人也更喜欢叫它们纤程(Fiber),或者绿色线程(GreenThread)。正如一个进程能够拥有多个线程同样,一个线程也能够拥有多个协程。

5.1 协程的目的

在传统的J2EE系统中都是基于每一个请求占用一个线程去完成完整的业务逻辑(包括事务)。因此系统的吞吐能力取决于每一个线程的操做耗时。若是遇到很耗时的I/O行为,则整个系统的吞吐马上降低,由于这个时候线程一直处于阻塞状态,若是线程不少的时候,会存在不少其余的线程处于等待,空闲状态(等待前面的线程执行完才能执行),形成了资源应用不完全。

最多见的例子就是JDBC(它是同步阻塞的),这也是为何不少人都说数据库是瓶颈的缘由。这里的耗时实际上是让CPU一直在等待I/O返回,说白了线程根本没有利用CPU去作运算,而是处于空转状态。而另外过多的线程,也会带来更多的ContextSwitch(上下文切换)开销。

而协程的目的就是当出现长时间的I/O操做时,经过让出(yield)目前的协程调度,执行下一个任务的方式,来消除ContextSwitch上的开销。

5.2 协程的特色

  1. 线程的切换由操做系统负责调度,协程由用户本身进行调度,所以减小了上下文切换,提升了效率
  2. 线程的默认Stack大小是1M,而协程更轻量,接近1K。所以能够在相同的内存中开启更多的协程。
  3. 因为在同一个线程上,所以能够避免竞争关系而使用锁
  4. 适用于被阻塞的,且须要大量并发的场景。但不适用于大量计算的多线程,遇到此种状况,更好实用线程去解决。

5.3 协程的原理

当出现IO阻塞的时候,由协程的调度器进行调度,经过将数据流马上yield掉(主动让出),而且记录当前栈上的数据,阻塞完后马上再经过线程恢复栈,并把阻塞的结果放到这个线程上去跑,这样看上去好像跟写同步代码没有任何差异,这整个流程能够称为coroutine,而跑在由coroutine负责调度的线程称为Fiber。好比Golang里的 go关键字其实就是负责开启一个Fiber,让func逻辑跑在上面。

因为协程的暂停彻底由程序控制,发生在用户态上;而线程的阻塞状态是由操做系统内核来进行切换,发生在内核态上。
所以,协程的开销远远小于线程的开销,也就没有了ContextSwitch上的开销。

 

5.4 总结和比较

比较项 进程 线程 协程
占用资源 随程序运行所需内存而变化 初始单位为1MB,固定不可变 初始通常为 2KB,可随须要而增大
调度所属 资源分配由OS完成 由 OS 的内核完成 由用户完成
切换开销 进程切换开销很大 涉及模式切换(从用户态切换到内核态)、16个寄存器、PC、SP...等寄存器的刷新等 只有三个寄存器的值修改 - PC / SP / DX.
性能问题 进程独立运行 稳健

资源占用过高,频繁建立销毁会带来严重的性能问题,
线程之间上下文切换带来性能问题

资源占用小,不会带来严重的性能问题,
在线程内部切换
数据同步 可经过进程间通讯进行数据交换 须要用锁等机制确保数据的一直性和可见性 不须要多线程的锁机制,由于只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只须要判断状态就行了,因此执行效率比多线程高不少。

进程:是系统调度和分配资源的最小单位,拥有本身独立的堆和栈,进程由操做系统调度进程。进程维护的是程序所包含的资源(静态资源), 如:地址空间,打开的文件句柄集,文件系统状态,信号处理handler等
线程:是CPU调度和分配任务的最小单位,拥有本身独立的栈,与同一个进程下的其余线程共享所属进程的堆,标准线程由操做系统调度。线程维护的运行相关的资源(动态资源),如:运行栈,调度相关的控制信息,待处理的信号集等
协程:拥有本身独立的栈,与同一个进程下的其余线程共享所属进程的堆,协程由程序员在协程的代码里显式调度;

参考连接:https://www.jianshu.com/p/80bde972196d

相关文章
相关标签/搜索