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

news/2024/9/28 21:00:29

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

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

下面是一个简单的例子:

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" << " ";co_yield_ct();  // 切出到主协程cout << "y" << " ";cout << "z" << " ";
}int main(void) {...  // 主协程co_resume(A);  // 启动协程 Aco_resume(B);  // 启动协程 Bco_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;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/65912.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

Blender快速入门教程1简介

0 简介Blender是最著名的 3D 计算机图形制作免费程序之一。有了 Blender,你可以创建角色、道具、环境以及你的想象力所能产生的几乎所有其他东西。它不仅可以创建对象。你还可以让它们运动起来。在动画中讲述一个故事,带领人们穿越你自己创造的世界,或者为一些视频片段添加特…

今天我有博客了!

今天我有博客了!我要把我的编程心得写下来。 今天,我先写了蜗牛打怪兽。我发现需要打的次数都是2^(n)-1,于是我用while循环求出是2的几次方,再用变量一直乘2,最后-1。以下是具体示例。接着,我写了POW。这题限制比较紧,所以不能直接算,得看c是奇数还是偶数:偶数比绝对值…

『模拟赛』csp-s模拟赛6

『模拟赛』csp-s模拟赛6『模拟赛』csp-s模拟赛6 挂分日寄:0+20+0+0 喵喵赛时对拍拍了10000个点都没拍出来,赛后一下就拍出错来了,我谔谔。 T1 DP喵~ 首先 sort 一遍方便处理 其实转移时加一个 abs 取绝对值就可,纯纯多此一举 设 \(f[i,j,1/0]\) 为前 \(i\) 个数中选 \(j\) …

树莓派pico rp2040 使用rust 在ssd1306上显示中文信息

使用u8g2-font + embedded-graphics ,在rp2040 pico上用 ssd1306输出中文信息在rp2040上用DHT22 + ssd1306显示温度信息,用 embedded-graphics库和ssd1306库来实现。但实现的效果不是很理想,无法在ssd1306屏幕上显示中文。为了解决这个问题,在github和crates.io上面找了几天…

typeScript 的第一步---安装

Node.js/浏览器,只认识JS代码,不认识TS代码,需要将TS代码转化为JS代码,然后才能运行。 安装命令:npm i -g typescript 或者 yarn global add typescript 注意:Mac电脑安装全局包时,需要通知添加sudo获取权限。sudo npm i -g typescript 验证安装是否成功:tsc -v 查…

为什么用 AWS CLI?因为我懒得点鼠标!

在这篇博客中,我们一起深入探索 AWS CLI 的世界,从零开始,逐步构建在云端的家园。将介绍 AWS CLI 的基本功能和使用场景,如何创建 IAM 用户、VPC、子网、安全组、EC2 实例等,甚至还会搭建一个应用负载均衡器(ALB)。无论你是初学者还是有一定基础的用户,都能通过本指南掌…

妙用编辑器:使用Notepad--正则表达式从命令结果报文快速生成新命令

应用场景 日常生活中有些维护场景,比如检查设备状态,执行查询命令后,得到精简结果报文,如果要更深入的检查状态,可能还要执行其他命令,逐个对象进行查询,这里涉及到快速从报文生成查询指令的功能。 比如有如下一个从LST 命令查询出来的报文,需要快速的生成DSP命令,逐个…

JavaScript深拷贝与浅拷贝

由于对象采用的是引用赋值。所以直接用“=”,修改属性的时候也会将原来的变量改变掉。 因此,就有了浅拷贝与深拷贝 用{...obj}和object.assign表示浅拷贝,其只拷贝外围对象的一层,而不会拷贝多层。 方法二:使用Object.assign 深拷贝的实现 其一是通过递归实现拷贝。其二lo…