1.什么是进程,什么是线程?

进程就是应用程序的启动实例。比如我们运行一个游戏,打开一个软件,就是开启了一个进程。

线程从属于进程,是程序的实际执行者。一个进程至少包含一个主线程,也可以有更多的子线程。

进程是资源分配的基本单位,线程是操作系统调度的基本单位。

而无论是进程还是线程,都是由操作系统所管理的,其Java中线程具有多种状态。而线程不同状态之间的转换是由谁来实现的呢?JVM通过操作系统内核中的TCB(Thread Control Block)模块来改变线程的状态,这一过程需要耗费一定的CPU资源。

2.进程和线程的痛点

线程之间是如何进行协作的呢?

最经典的例子就是生产者/消费者模式。若干个生产者线程向队列中写入数据,若干个消费者线程从队列中消费数据。

但上面虽然正确实现了生产者/消费者模式,但并不是一个高性能的实现。为什么性能不高呢?

  • 涉及到同步锁;
  • 涉及到线程阻塞状态和可运行状态之间的切换;
  • 涉及线程的上下文切换;

以上涉及到的任何一点,都是非常耗费性能的操作的。

3.什么是协程呢

协程,是一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程。

最重要的是,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态中执行)。

这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。

既然协程这么好,它到底是怎么来使用的呢?

由于Java的原生语法中并没有实现协程(某些开源框架实现了协程,但是很少被使用),所以我们来看一看python当中对协程的实现案例,同样以生产者消费者模式为例:

在这里插入图片描述

其中 yield 是python当中的语法。当协程执行到yield关键字时,会暂停在那一行,等到主线程调用send方法发送了数据,协程才会接到数据继续执行。

但是,yield让协程暂停,和线程的阻塞是有本质区别的。协程的暂停完全由程序控制,线程的阻塞状态是由操作系统内核来进行切换。

因此,协程的开销远远小于线程的开销。

在这里插入图片描述

协程是一种用户态的轻量级线程。协程的调度完全由用户控制,协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其它地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

进程与协程的比较

  • 一个线程可以有多个协程,一个进程也可以单独拥有多个协程;
  • 线程进程都是同步机制,而协程则是异步机制;
  • 协程能保留上一次调用的状态,每次重入时,就相当于进入上一次调用的状态;
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐