【Linux】协程简介

【Linux】协程简介

  • 一、什么是协程?
    • 简介
    • 优点
  • 二、为什么使用协程?
  • 三、协程的种类
    • 1、对称协程
    • 2、非对称协程
  • 四、协程栈
    • 1、静态栈
    • 2、分段栈
    • 3、共享栈
    • 4、虚拟内存栈
  • 五、协程调度
    • 1、栈式调度
    • 2、星切调度
    • 3、环切调度
  • 六、常见协程库
  • 参考文献

一、什么是协程?

首先回忆一下线程的概念:
线程是操作系统能够进行运算调度的最小单位。被包含在进程之中,是进程的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程可以并发执行多个线程,每个线程会执行不同的任务。

简介

  • 协程可以理解为一种用户态的轻量级线程,切换由用户定义,各任务之间可以控制执行暂停恢复函数,来达到多任务协作的目的;
  • 协程上下文切换速度快, 且不会陷入内核态
  • 协程拥有独立的寄存器上下文和栈,协程调度切换时,将寄存器上下文和栈,在来回切换时,恢复先前保存的寄存器上下文和栈。
  • 一个线程中可以有多个协程,协程是运行在线程之中的逻辑处理单元。协程在线程里的运行是串行的。
  • 协程之间的调度通过调度器或者自己主动放开对CPU的占有,让给其他协程。

优点

  • 协程具有极高的执行效率,由于子程序切换不是线程切换,是由程序自身控制,故协程没有线程切换的开销;
  • 多线程的线程数越多,协程的性能越显著
  • 访问共享资源不需要使用多线程的锁机制和变量冲突,由于只有一个线程,故在协程只需要判断状态即可,降低了编码难度;
  • 同步代码的方式写异步逻辑;

二、为什么使用协程?

为什么使用协程,我们先从server框架的实现说起,对于client-server的架构,server最简单的实现如下。即串行地接收连接、读取请求、处理、应答。该实现弊端显而易见,server同一时间只能为一个客户端服务。

while(1) {accept();recv();do();send();}

为充分利用好多核cpu进行任务处理,我们有了多进程/多线程的server框架,这也是server最常用的实现方式
accept进程 - n个epoll进程 - n个worker进程

  • accpet进程处理到来的连接,并将fd交给各个epoll进程
  • epoll进程对各fd设置监控事件,当事件触发时通过共享内存等方式,将请求传给各个worker进程
  • worker进程负责具体的业务逻辑处理并回包应答

以上框架以事件监听、进程池的方式,解决了多任务处理问题,但我们还可以对其作进一步的优化。

进程/线程是Linux内核最小的调度单位,一个进程在进行io操作时 (常见于分布式系统中RPC远程调用),其所在的cpu也处于iowait状态。直到后端svr返回,或者该进程的时间片用完、进程被切换到就绪态。是否可以把原本用于iowait的cpu时间片利用起来,发生io操作时让cpu处理新的请求,以提高单核cpu的使用率?

协程在用户态下完成切换,由程序员/调度器完成调度,结合对socket类/io操作类函数挂钩子、添加事件监听,为以上问题提供了解决方法。

三、协程的种类

协程目前分两种,一种是go语言采用的对称协程;一种是libco采用的非对称协程
yield: 协程执行到⼀半就退出,暂时让出CPU执行权
resume: 协程重新恢复运行

1、对称协程

这里借用知乎博主tx征服者的图来向大家说明:
在这里插入图片描述

对称协程其实就是由协程调度器来负责,协程不允许调度其他协程。 调度器resume协程A,那么协程A会yeild回调度器,再由调度器去执行其他的协程。如果我们把resume的虚线都放在左边,yeild的实线都放在右边。以调度器为中心,那么他是不是就是一个对称的图形呢?

2、非对称协程

我们再来看一下非对称协程
在这里插入图片描述
非对称调度由调度器来调度协程A,然后协程A再调动协程B。 那么Byeild让出CPU使用权就不是让给调度器了,而是协程A。简而言之就是从哪儿来,回哪儿去。同样,将此展开也不是一个对称的图形了。

四、协程栈

1、静态栈

固定大小的栈,容易造成溢出等现象。

2、分段栈

插入栈内存检测代码,若栈不够用,则申请新内存扩展;但该方法难以在第三方库中进行使用。

3、共享栈

申请一块大内存作为共享栈,在运行前,先把协程栈的内存copy到共享栈中,运行结束后再计算协程栈真正使用的内存,copy出来保存起来,这样每次只需保存真正使用到的栈内存量即可。

优点:该方案极大程度上避免了内存的浪费,做到了用多少占多少,同等内存条件下,可以启动的协程数量更多。

缺点:但该方案在copy上花费了时间,降低速度,导致协程切换慢。

4、虚拟内存栈

机制:进程申请的内存并不会立即被映射成物理内存,而是仅管理于虚拟内存中,真正对其读写时会触发缺页中断,此时才会映射为物理内存;
可以做到用多少占多少,冗余不超过一个内存页大小。

五、协程调度

1、栈式调度

协程队列是一个栈式结构,创建的协程都置于栈顶,并且会立即暂停当前协程并切换至子协程中运行,子协程运行结束后,继续切换回来执行父协程;越是栈底部的协程,被调度到的机会将越少,甚至出现只有栈顶的协程在互相切换。

2、星切调度

调度线程 -> 协程A -> 调度线程 -> 协程B -> 调度线程 -> …
将当前可调度的协程组织成队列,按顺序从头部取出协程调度;新协程则从尾部入队,调度后再将协程从尾部入队。

3、环切调度

调度线程 -> 协程A -> 协程B -> 协程C -> 协程D -> 调度线程 -> …
从调度顺序上可知,环切的切换次数仅为星切的一半,可以提高整体切换速度;但在多线程调度、WorkSteal方面会带来一定的挑战。

六、常见协程库

boost.context
提供了上下文的抽象,并给了两种方式,fiber和call/cc的方式保留和执行上下文切换;
性能佳,推荐使用,切换性能可达到1.25亿次/秒。

boost.coroutine
提供的协程只能单向传递数据,数据只能单向的从一个代码块流向另一个代码块。流入流出分别对应着push_type和pull_type类型,由这两个类型组成协程间跳转的通道,同时也是数据传递的通道。

ucontext
该库是在unix下提供的,使用是最安全可靠,但性能较差,大概200万次/秒。

fiber
该库是在window下提供的,与ucontext类似。

libco
腾讯开源的c++协程库。

libgo
libgo为了有更广阔的适用性,支持了多线程调度、HookSyscall、Worksteal等,同时突破了传统协程库仅用来处理网络io密集型业务的局限,也能适用于cpu密集型业务,充当并行编程库来使用。

参考文献

协程 及 libco 介绍
ucontext-人人都可以实现的简单协程库
协程学习(对称和非对称)
Linux【协程】 | 常见协程库简介

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习 | 模型评估和选择 各种评估指标总结——错误率精度-查准率查全率-真正例率假正例率 PR曲线ROC曲线

文章目录 1. 如何产生训练集和测试集呢?1.1 留出法1.2 K折交叉验证法1.3 自助法 2. 模型评估指标2.1 错误率和精度2.2 查准率和查全率与F12.2.1 PR曲线及其绘制 2.3 正例率和假例率2.3.1 ROC曲线图绘制及AUC 3 假设检验 1. 如何产生训练集和测试集呢? 1…

【ACW 服务端】k8s部署

k8s部署 --- apiVersion: apps/v1 kind: Deployment metadata:annotations:k8s.kuboard.cn/displayName: 【wu-smart-acw-server】后台服务端labels:k8s.kuboard.cn/layer: svck8s.kuboard.cn/name: wu-smart-acw-servername: wu-smart-acw-servernamespace: defaultresourceV…

记autodl跑模型GPU CPU利用率骤变为0问题

目录 问题 解决 问题 实验室服务器资源紧张,博主就自己在autodl上租卡跑了,autodl有一个网络共享存储,可挂载至同一地区的不同实例中,当我们在该地区创建实例开机后,将会挂载文件存储至实例的/root/autodl-fs目录…

韩国量子之梦:将量子计算纳入新增长 4.0战略

内容来源:量子前哨(ID:Qforepost) 编辑丨王珩 编译/排版丨沛贤 深度好文:1500字丨9分钟阅读 据《朝鲜邮报》报道,韩国将推出由量子计算加速的云服务,并在首尔地区启动城市空中交通的试飞&…

微信小程序订阅消息前后端示例

微信小程序的订阅消息&#xff0c; 必须是由弹框&#xff0c;弹框&#xff0c;弹框来调起了&#xff0c;单纯的在页面上调用 wx.requestSubscribeMessage是没有效果的 小程序端的代码 <view class"sub" bindtap"dinyuxiaoxi">订阅消息</view>…

Leetcoder Day27| 贪心算法part01

语言&#xff1a;Java/Go 理论 贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 什么时候用贪心&#xff1f;可以用局部最优退出全局最优&#xff0c;并且想不到反例到情况 贪心的一般解题步骤 将问题分解为若干个子问题找出适合的贪心策略求解每一个子…

【Linux系统化学习】信号概念和信号的产生

目录 信号的概念 从生活中的例子中感知信号 前台进程和后台进程 前台进程 后台进程 操作系统如何知道用户向键盘写入数据了&#xff1f; 进程如何得知自己收到了信号&#xff1f; 信号捕捉 signal函数 Core Dump&#xff08;核心转储&#xff09; 信号产生的方式 通…

LeetCode 刷题 [C++] 第102题.二叉树的层序遍历

题目描述 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 题目分析 题目中要求层序遍历二叉树&#xff0c;即二叉树的广度优先搜索(BFS)。BFS一般使用队列的先入先出特性实现&#…

react倒计时功能

目录 类组件写法 函数组件写法&#xff1a; demo: 手机获取验证码登录&#xff08;验证码60秒倒计时&#xff09; react倒计时5 秒 React中的倒计时可以通过使用setInterval()函数来实现。下面是一个示例代码&#xff1a; 类组件写法 import React from react; import { But…

【Docker】狂神说

图片后补 官网&#xff1a; https://www.docker.com/ Docker概述 Docker为什么出现 原因&#xff1a;环境配置不能跨平台 方案 传统方式&#xff1a;jar&#xff08;开发人员&#xff09; 部署&#xff08;运维人员&#xff09; 解决方式&#xff1a;开发打包上线一套流程 …

Qt SQLite的创建和使用

重点&#xff1a; 1.SQLite创建数据库内容方法 链接&#xff1a;SQLite Expert Personal的简单使用-CSDN博客 2.和数据库进行链接方法 QSqlDatabase DB; //数据库连接bool MainWindow::openDatabase(QString aFile) {DBQSqlDatabase::addDatabase("QSQLITE"); /…

使用uniapp开发时自定义tabbar

预览图&#xff1a; 一、配置page.jsong中的tabbar&#xff08;这一步是必须的&#xff0c;因为我们在使用uni.switchTab()时必须要用到&#xff09; "tabBar": {"list": [{"pagePath": "pages/index/index","iconPath": &…

java回顾总结--代理模式

目录 一、代理模式1.1 静态代理示例 1.2 动态代理示例 二、总结 一、代理模式 1.1 静态代理 代理模式给某一个对象提供一个代理对象&#xff0c;并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。比如你按照小卡片上的电话打过去寻求服务&#…

C# 学习第四弹——字符串

一、char类型的使用 字符使用单引号&#xff0c;单个字符 转义字符是一种特殊的字符变量&#xff0c;以反斜线开头&#xff0c;后跟一个或多个字符。 输出多级目录可以使用 二、字符串的声明和初始化 1、引用字符串常量 引用字符串常量初始化——字符使用单引号&#xff0…

加密与安全_探索常用编码算法

文章目录 概述什么是编码编码分类ASCII码 &#xff08;最多只能有128个字符&#xff09;Unicode &#xff08;用于表示世界上几乎所有的文字和符号&#xff09;URL编码 &#xff08;解决服务器只能识别ASCII字符的问题&#xff09;实现&#xff1a;编码_URLEncoder实现&#xf…

K8S常用kubectl命令汇总(持续更新中)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

【Prometheus】基于Altertmanager发送告警到多个接收方、监控各种服务、pushgateway

基于Altertmanager发送报警到多个接收方 一、配置alertmanager-发送告警到qq邮箱1.1、告警流程1.2、告警设置【1】邮箱配置【2】告警规则配置【3】 部署prometheus【4】部署service 二、配置alertmanager-发送告警到钉钉三、配置alertmanager-发送告警到企业微信3.1、注册企业微…

量子算法入门—4.量子比特与量子门(1)

1.量子比特 经典比特和量子比特 经典比特只有0、1两种取值&#xff0c;非黑即白&#xff0c;有n位即 2 n 2^n 2n种可能量子比特使用0、1的量子态描述量子比特的状态&#xff0c;可以通过线性组合形成新的量子态&#xff0c;就像光谱可以调节成分 引入线代记法&#xff0c;0、…

ARK:《BIG IDEAS 2024》

Cathie Wood所带领的方舟投资&#xff08;ARK&#xff09;发布了年度重磅研究报告《BIG IDEAS 2024》&#xff0c;该报告指出人工智能、公共区块链、多组学测序、能源存储和机器人技术这五大板块的融合将带来全球经济活动的改变。 这五个创新平台正在融合并定义这个技术时代&am…

92. 递归实现指数型枚举 刷题笔记

思路 dfs 考虑选或者不选每个位置 用0表示未考虑 1表示选 2表示不选 用u表示搜索状态 u>n时 已经搜到底层了 需要输出当前方案 遍历 如果选了则输出 #include<iostream> using namespace std; int n; const int N16; int st[N]; void dfs(int u){ //u来记…