协程概览

什么是协程

我们可以简单的认为:协程就是用户态的线程,但是上下文切换的时机是靠调用方(写代码的开发人员)自身去控制的;

同时,协程和用户态线程非常接近,用户态线程之间的切换不需要陷入内核,但部分操作系统中用户态线程的切换需要内核态线程的辅助;

比如下面是一个简单的例子:

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库(c++的协程库)把这个改造一下

void A() {
   cout << 1 << " ";
   cout << 2 << " ";
   co_yield_ct();  // 切出到主协程
   cout << 3 << " ";
}

void B() {
   cout << "x" << " ";
   co_yield_ct();  // 切出到主协程
   cout << "y" << " ";
   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

切出跳出操作,协程中称之为yield 恢复和启动则称之为resume

那么为什么使用协程而不是多线程?

因为线程的操作太重量级了,而在当前的情况下,我们只是希望先暂停当前任务,等待io好了之后再切回来

协程的优缺点:

  • 减少了线程的重复高频创建;
  • 尽量避免线程的阻塞;
  • 让原来要使用异步+回调方式写的非人类代码,可以用看似同步的方式写出来,提升代码的可维护与可理解性(毕竟不需要考虑多线程那一套东西了)

缺点:

⽆法利⽤多核资源。线程才是系统调度的基本单位,单线程下的多协程本质上还是串⾏执⾏的,只能⽤到单核
计算资源,所以协程往往要与多线程、多进程⼀起使⽤。

协程的分类

对称协程与⾮对称协程

对称协程,协程可以不受限制地将控制权交给任何其他协程。任何⼀个协程都是相互独⽴且平等的,调度权可以在任意协程之间转移

⾮对称协程,是指协程之间存在类似堆栈的调⽤⽅-被调⽤⽅关系。协程出让调度权的⽬标只能是它的调⽤者。

有栈协程与⽆栈协程

有栈协程:⽤独⽴的执⾏栈来保存协程的上下⽂信息

⽆栈协程:它不需要独⽴的执⾏栈来保存协程的上下⽂信息,协程的上下⽂都放到公共内存中,当协程被挂起时,
⽆栈协程会将协程的状态保存在堆上的数据结构中,并将控制权交还给调度器。

posted @ 2024-02-07 20:12  LiviaYu  阅读(51)  评论(0)    收藏  举报