什么是协程
协程(coroutine)是一种用户态的轻量级线程。在Linux中, 进程分为内核态和用户态两种。简单些来说,协程就是程序自身的控制调度,而线程则是操作系统内核控制调度。这就免去了线程用户态到内核态切换的开销。
同时,因为协程是程序自身来控制调度,提高了资源利用率,协程之间的切换成本也极大降低了。协程本质是可以暂停和恢复的函数,能够在单线程内实现多任务迸发执行。
线程的创建、暂停、恢复、销毁完全由内核控制。而协程的创建、暂停、恢复、销毁完全由用户程序控制,不依赖内核调度;切换协程时也就无需要陷入内核态。这里再次说明了协程的切换成本极低;协程的切换成本仅有保存和恢复少量的上下文(如寄存器状态、程序计数器)。
协程可以在执行过程中主动暂停(通过yield、await等关键字),同时保留其局部变量和执行状态,再将控制权交还给其他协程,之后可以从暂停的位置恢复执行。
协程的执行仍然需要在线程上被执行,因为线程是现代操作系统的调度。多个协程通常运行在一个线程中(共享线程资源),通过”协作式调度“,而非抢占式,交替执行。一个协程主动暂停后,另一个协程才会获得执行机会,这避免了线程切换的内核开销和资源竞争的问题。
一个协程占用的内存不是很大,通常只有几KB,而一个线程中可以创建数万甚至数十万个协程(迸发规模巨大),而线程的内存占用通常以MB为单位,而线程的数量受到操作系统的限制。
协程适合I/O密集型的任务,为什么这么说呢?比如网络请求、文件读写等这些任务大部分时间都在等待I/O的完成(而不是CPU计算),在这一段时间,协程可以主动暂停,让其他协程执行,有效避免了让线程空等,提高了CPU的利用率。
协程也适合高并发场景,像服务器处理大量并发请求(API接口、Web服务),无需要创建同等数量的线程(线程资源很快会耗尽,使用协程就可以避免这个问题)。
协程的暂停,恢复机制可以简化复杂流程的代码逻辑,比回调函数更直观。
协程的本质是可暂停/恢复的函数,要实现协程机制,必须依赖三个关键机制:
1.要有独立栈空间:每个协程需要有自己的栈,目的是为了避免与主程序栈发生冲突;
2.要有上下保存/恢复机制,保存当前寄存器、程序计数器等状态;
3.调度逻辑:简单的调度器决定哪个协程获得执行权
