进程那些事系列-何为协程

在讲协程前, 我们先点名几个概念

并行和并发

摘自知乎的一个例子:

  1. 你正在吃饭, 当你电话来了, 你一直到吃完了才去接电话 =》 不支持并发和并行
  2. 你正在吃饭, 当你电话来了, 你放下筷子, 去接电话, 打完后继续吃饭 =》支持并发
  3. 你正在吃饭, 当你电话来了, 你一边接电话, 一边吃饭 =》 支持并行

并发和并行都有处理多任务的能力(吃饭和接电话), 但两者的区别在于是否能同时

  • 并发的关键是你能处理多任务, 但不是同时
  • 并行的关键是你能同时处理多任务, 任务的最大上限取决于CPU的核数

用户态和内核态

还记得进程结构吗?


process structure

一个进程实例地址被分成了两部分, 内核空间 和 用户空间. 在32位的内存中, 每个进程最高的1G空间称自为内核空间, 供所有进程共享. 而剩下的3G称自为用户空间, 供自己使用

CPU指令集也一样, CPU的所有指令中, 有些指令是非常危险的, 如果错用, 将导致系统崩溃(比如,清理内存, 设置时钟等). 所以我们将指令分成两个等级: 特权指令 和 非特权指令.

无论是内核空间还是特权指令, 都统一交给操作系统的核心 内核 来负责, 它独立于普通应用,可以访问被保护的内存空间地址(内核地址), 也有访问底层硬件的权限.

内核态是提供给内核的运行空间, 而用户态是提供给应用程序运行的空间, 两者所能使用的指令和内存都是不一样的, 这样有效地保护了操作系统的安全, 当程序崩溃时, 不会影响到操作系统

这里你就会纳闷, 好端端的运行程序, 为什么会进入到内核态?
用户态进入内核态的三种方式:

  • 系统调用(System Call)
  • 缺页中断(相应的虚拟地址没有映射到物理地址)
  • 中断(网络, I/O)

系统调用相当于用户态和内核态的中介, 为了使用户态的程序能够访问到内核管理的资源(CPU, 磁盘等), 内核提供的一组通用访问接口, 这些接口就叫做 系统调用

image.png

当用户态进入内核态 或者 内核态进入用户态 都需要进行上下文(CPU上下文)切换的, 所以一次系统调用会产生两次 CPU上下文切换.

协程

协程是什么?

协程, 英文Coroutines, 是一种比线程更轻量级的存在. 正如一个进程可以有多个线程, 一个线程也可以有多个协程. 它的特性体现在 它不是由操作系统内核来管理, 而完全由程序所控制
这点引用特性出了它的核心, 程序所控制. 这会导致在进行协程切换的时候, 我们不需要从用户态到内核态, 这无形中就减少了CPU上下文切换所带来的消耗

尽管线程是轻量级的进程, 它共享着进程的资源, 但它的切换是由内核来管理的, 这就意味着每次切换都需要从用户态(线程A)到内核态, 再从内核态到用户态(线程B), 避免不了CPU带来的消耗

协程是早年间就有的东西, 但直到现在才开始流行, 这其中的原由离不开 - 高并发

高并发下的协程

随着互联网流量的不断增大, 请求从百万到千万甚至更多. 高并发下的技术也一直在演变. 从早期的 多进程 -> 多线程 -> NIO(多路复用, 异步回调) -> 协程
本段参考 05 | 协程:如何快速地实现高并发服务当我们在讨论高并发的时候, 在讨论着什么, 侵权则删

image.png

无论是多线程还是多进程, 当我们发起I/O请求时, 会导致线程的阻塞, 等待请求完成. 这个时候内核就会进行线程切换, 等到 I/O 响应时, 再切换回来

一说到切换, 开销就少不了. 特别是面对千万请求时, 这样的开销是机器无法承受的. 人们提出了新的想法, 即如何避免切换?, 或者说如何避免阻塞

image.png

陶老师提到很关键的一点, 把内核实现切换的请求工作, 转换到用户态来完成.

异步化编程通过一个叫做 Dispatcher 的单线程主循环(又叫 event loop), 用户向 Dispatcher 注册回调函数, 来实现异步通知, 从而不必在原地干等消费资源. 整个过程由单线程来实现, 在Dispatcher主循环中通过 select()/ epoll() 等系统调用来等待各种I/O事件的发生, 并调用相应的回调函数(event handle)来处理请求

通过将阻塞方法改造程了非阻塞方法, 和单线程的使用, 将并发提升到了百万级请求级别. 但是异步化代码容易出错, 而且callback的回调地狱也让人头疼, 阻塞函数都需要经过非阻塞系统拆分成了两部分, 第一个函数由你发起, 第二个函数由多路复用机制调用, 导致代码太过于复杂和晦涩

这时候, 人们把目光指向了协程

A coroutine is a function that can suspend its execution (yield) until the given YieldInstruction finishes.

协程和异步化编程一样, 都是通过用户态来调度. 官方的定义中把 协程比做了函数, 这个函数在执行时, 如果遇到了阻塞, 会使执行它的协程无感知的自动放弃执行权, 由协程框架切换到其他就绪的协程继续执行, 当结果满足后, 该框架选择合适的时机后切换回它所在的协程继续执行

这里又引出了协程的另一大好处, 即用同步编程的方式来写高并发程序

协程的切换类似于内核的切换, 保存两个最重要的寄存器值(指令寄存器, 栈寄存器). 协程都有自己的栈, 是从进程的堆中分配的, 很小很小一块. 这也是为什么说, 一个线程能运行百万个协程

协程的优缺点

协程的优点: 我们在总结下

  • 协程更轻量, 内存消耗下, 创建成本小
  • 协程大大减少了上下文切换的消耗
  • 减少同步加锁, 这个是很关键的一点. 因为协程是协作式任务分配, 就自己主动放弃, 让别人接着运行. 而线程是抢占式的
  • 按照同步的思维来写异步代码

缺点:

  • 在协程中不能有阻塞操作, 否则会导致整个线程阻塞(因为要自己主动放弃, 如果阻塞了, 怎么放弃)
  • 协程可以处理I/O密集型应用, 对CPU密集型不得行(因为CPU密集型一直在算, 哪有时间切换给其他协程)

总结

协程到了就差不大了, 其实主要是理解它的思想和应用. 之所以会不断运用新技术, 也是因为为了更好的压榨CPU的有效使用

最后, 我们来看看 协程 和 线程的关系
这两者其实并不是互相排斥的, 在很多场景, 都会有 协程 + 线程的结合. 比如当我们遇到无法将阻塞改成非阻塞状态的函数时, 我们需要线程的调用. 其次, 无论开多少个协程, 本质上使用的是一个线程, 那用的就是单核CPU, 我们需要借助多线程来使用多核CPU

如果有什么疑问和错误, 欢迎指出, 感谢你的支持

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270