问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

一文彻底搞懂协程(coroutine)是什么

创作时间:
作者:
@小白创作中心

一文彻底搞懂协程(coroutine)是什么

引用
1
来源
1.
https://www.cnblogs.com/java-six/p/18438384

协程(Coroutine)是一种轻量级的执行单元,它可以在单个线程中实现多任务的切换和执行。本文将从协程的基本概念、特点、与线程和进程的关系等方面,深入浅出地讲解协程的工作原理和应用场景。

什么是协程

总结:程序员可以控制的,类似用户级线程

我们可以简单的认为:协程就是用户态的线程,但是上下文切换的时机是靠调用方(写代码的开发人员)自身去控制的。
同时,协程和用户态线程非常接近,用户态线程之间的切换不需要陷入内核,但部分操作系统中用户态线程的切换需要内核态线程的辅助。

下面是一个简单的例子:

void A() {
   cout << 1 << " ";
   cout << 2 << " ";
   cout << 3 << " ";
}
 
void B() {
   cout << "x" << " ";
   cout << "y" << " ";
   cout << "z" << " ";
}
 
int main(void) {
  A();
  B();
}

在单线程中,上述函数的输出为:

1 2 3 x y z

如果我们用 libco 库将上面程序改造一下:

void A() {
   cout << 1 << " ";
   cout << 2 << " ";
   co_yield_ct();  // 切出到主协程
   cout << 3 << " ";
}
 
void B() {
   cout << "x" << " ";
   cout << "y" << " ";
   co_yield_ct();  // 切出到主协程
   cout << "z" << " ";
}
 
int main(void) {
  ...  // 主协程
  co_resume(A);  // 启动协程 A
  co_resume(B);  // 启动协程 B
  co_resume(A);  // 从协程 A 切出处继续执行
  co_resume(B);  // 从协程 B 切出处继续执行
}

同样在单线程中,改造后的程序输出如下:

1 2 x 3 y z

可以看出,切出操作是由 co_yield_ct() 函数实现的,而协程的启动和恢复是由 co_resume 实现的。函数 A() 和 B() 并不是一个执行完才执行另一个,而是产生了 “交叉执行“ 的效果,这就是通过协程实现的!

线程挺好的,我们为什么需要协程呢?
因为有些时候我们在执行一些操作(尤其是IO操作)时,不希望去做“创建一个新的线程”这种重量级的操作来异步处理。而是希望:在当前线程执行中,暂时切换到其他任务中执行,同时在IO真正准备好了之后,再切换回来继续执行!

相比于多开一个线程来操作,使用协程的好处:

减少了线程的重复高频创建;

尽量避免线程的阻塞;

提升代码的可维护与可理解性(毕竟不需要考虑多线程那一套东西了);

同时,下面是一些协程的特点:

协程可以主动让出 CPU 时间片;(注意:不是当前线程让出 CPU 时间片,而是线程内的某个协程让出时间片供同线程内其他协程运行;)

协程可以恢复 CPU 上下文;当另一个协程继续执行时,其需要恢复 CPU 上下文环境;

协程有个管理者,管理者可以选择一个协程来运行,其他协程要么阻塞,要么ready,或者died;

运行中的协程将占有当前线程的所有计算资源;

协程天生有栈属性,而且是 lock free;

协程、线程和进程之间的关系

协程、线程、进程之间的关系和比较

特性
进程
线程
协程
执行单位
独立的执行单元
进程内的执行单元
线程内的执行单元
内存空间
独立内存空间
共享进程内存空间
共享线程内存空间
切换开销
较低
最低
通信方式
IPC(进程间通信)
共享内存
共享内存、共享状态
调度方式
由操作系统内核调度
由操作系统内核调度
由用户程序自行调度
并发/并行性
并发和并行
并发和并行
并发(单线程),多线程可并行
应用场景
独立程序、服务器进程等
多任务处理、并发编程
IO 密集型任务、异步编程

协程、线程、进程的关系总结

  • 进程包含线程: 一个进程可以包含多个线程,线程是进程的组成部分,多个线程共享进程的资源。
  • 线程包含协程: 一个线程可以包含多个协程,协程是在用户态实现的轻量级线程,可以在单个线程内部实现多任务切换。
  • 协程与线程、进程的区别: 协程与线程、进程最大的区别在于调度方式。进程和线程由操作系统调度,协程由用户程序自行调度,切换更加高效。

适用场景

  • 进程: 适用于需要高隔离度、稳定性较高的场景,比如独立服务、数据库等。
  • 线程: 适用于计算密集型任务、多任务并发执行、利用多核 CPU 的场景,比如 Web 服务器、数据处理等。
  • 协程: 适用于 IO 密集型任务、异步编程、轻量级多任务切换的场景,比如网络爬虫、异步框架等。
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号