什么是协程?

1. 为什么我们需要协程?

要解释协程的由来,需要从最早的进程说起。

1.1 非抢夺式任务与抢夺式任务

在比较早的操作系统中,使用的是非抢夺式任务,也叫协作式任务,在这种任务方式下,后台进程的执行依赖于当前线程主动让出执行权,如果当前进程一直不让(例如陷入了死循环、一直等待遇到故障的网络报文)等,就会导致整个系统出现故障。

在这种背景下抢夺式任务应运而生,他给每个进程分配一个时间片,时间片用完就会强制休眠。或者虽然时间片没到,但是有更高优先级的任务出现了,也会被操作系统强制休眠。这么做能够提高整个系统的容错率:一个进程出了问题,会被操作系统强制剥夺执行权来确保其他任务的正常运行。
总结下来

  • 非抢夺式任务:多个进程独立运行,每个进程需要选取时机主动让出控制权,这种场景下如果每个进程都遵守规定,适时释放资源,就能将系统资源的利用最大化,但如果有一个进程不遵守规定,整个系统便会崩溃。
  • 抢夺式任务:操作系统将CPU时间公平的分配给每个应用,并对用完CPU时间的任务执行强制休眠,避免某几个进程影响整个系统的正常运行

1.2 进程与线程

在计算机技术的发展过程中,系统逐渐从单CPU变为多CPU,这时候就出现了很多新的应用场景。例如一边从网络上下载视频,一边使用播放器观看,每个进程跑在各自的CPU上,最大化的利用好硬件资源。
新的功能同样带来新的问题:进程之间的同步问题,为了保证下载进程和播放进程的一致,进程之间必须要约定好共享内存的格式、数据存储的位置、使用的锁等等,这是一个很繁琐的事情。
因此就会想到,如果下载数据和播放数据这件事情能放到同一个进程里,那同步的事情或许会容易许多,但是一个进程又无法充分利用多个核的硬件资源,怎么办呢?
于是就出现了线程。
与进程一样,线程和进程都需要在OS进行注册,接受OS的调度,以此来充分利用多CPU的资源,同时线程也吸收了前人(进程)的经验,从一开始就是抢夺式任务。

1.3 协程

线程的出现让单进程也能充分利用多CPU的资源,但因其延续了进程抢夺式任务的设计,同样也带来了一些问题。
还记得原本进程为什么要设计成抢夺式任务吗?主要目的是为了防止一些恶劣进程或者故障进程影响整个系统的运行,而多线程之间的交互往往在同一个进程中,又同一拨人开发,所有的线程都处于同一个开发者的控制指一下,在这种情况下,大多数情况也就不存在所谓“恶劣进程”、“故障进程”了,抢夺式任务的优势一下子就没有这么大了。
相对的,抢夺式任务的劣势变得更突出了,因为OS会强制剥夺线程的执行权,因此线程也存在时许紊乱的问题,同一个进程的线程之间依然要做同步操作(当然,这比进程之间的同步要简单很多)。
在这个背景下,非抢夺式任务的优势就体现出来了,如果每个任务都遵守规定,适时释放资源,那系统的资源利用率将会被最大化,这件事情在有不同开发者的OS上很难办到,但是在同一个进程的不同线程上,办到还是不难的。非抢夺式任务使任务之间的交接点变得明确,当一段逻辑没有完全执行完成时,便不会交出执行权,也就不存在“尚未提交”的修改,那也就不需要锁了。
协程的提出,就是为了在线程之上实现非抢夺式任务。
协程本质上就是在用户空间实现的协作式多线程架构,协程的存在不被OS知道,因此不支持多核CPU的调度,但也因此不存在执行绪紊乱的问题。
同一个线程上可以支持多个协程,协程的执行顺序虽然无法确定,但是协程执行权的切换只会发生在用户明确放弃执行权之后,因此协程可以做到在完成了一次完全的数据修改之后再放弃执行权,在此期间不用担心任何其他的协程可能会中途读取或者修改。
这么一来,就能解释清楚,为什么我们需要协程了。

2. 协程的使用场景

说了这么多,那我们具体在什么时候可能需要用到协程呢?
最主要的场景是应用当我们需要大量线程来提高并发的时候,可以利用协程来减少线程数。
例如我们的服务器需要1w的并发去查询,但是1w个线程需要占用大量的内存,过多的线程切换会带来大量的上下文切换开销,占用很多的系统时间,此时我们可以使用100个线程,每个线程100个协程的方式。因为协程是用户态的操作,不涉及内核态,协程的切换代价要比线程更小,也不会带来太多的内存开销。

3. 注意事项

使用协程重要的作用是在等待IO的过程中可以重复利用线程,但是协程调用的如果是一个阻塞IO,操作系统就会让线程进行阻塞状态,之前说过,协程的存在是操作系统感知不到的,所以当协程调用了阻塞IO之后,操作系统就会将整个线程置为阻塞——那这个线程之上的其他协程也得不到执行了。
对于这种问题,一般有两种解决方式:

  • 调用阻塞IO的时候,重新启动一个线程去执行,执行完之后由协程读取,但这样的方式就和多线程没有太大的区别了,我们仍然需要很多的线程来提高并发。
  • 对系统IO进行封装,改成异步调用。这步需要大量工作,最好是编程语言能够支持。
posted @ 2022-12-08 00:01  Hugh_Locke  阅读(652)  评论(0编辑  收藏  举报