举重若轻 发表于 2023-5-28 18:18:36

协程概述讲解

协程

线程分为用户级线程,内核级线程和轻量级线程。Linux中使用的是轻量级线程,而协程虽然是运行在线程之上,但是是run在用户空间。并且协程和线程一样,拥有自己的调度器、cpu的上下文切换等。
协程在我个人看来是一种用户级线程;

[*]这是因为对于cpu有上下文的切换,而且是在用户空间的层次进行数据处理;一旦被内核的代码阻塞,是无法进行解除阻塞状态;
协程的功能

首先需要明确一点,协程是干嘛的,针对的事物是什么?

[*]协程针对的是IO处理,可以将多个同步关系的IO处理的性能接近于异步IO的效率;
[*]这样既保证了编写代码的逻辑,又保证了代码执行的效率;
异步IO的效率高,是正常的,因为调用某个IO函数,也就是系统调用,根据异步IO模型中的描述,它不会被阻塞且处理完毕后会通知调用线程,也就是异步IO模型没有阻塞时间。
协程的做法

那么问题就来了,应该是一个什么样的逻辑处理同步IO,才能让其性能接近异步IO呢?

[*]消除同步IO被阻塞住时的等待时间,从而让效率无限接近于异步IO。
[*]这就是协程干的功能,一旦被阻塞住了,就会把cpu让出给其他可以执行的协程。
cpu切换上下文过程

协程由运行体和调度器组成。
协程的运行体中保存着让出后的寄存器状态,方便于之后恢复、子过程函数和其参数、自身协程的状态、栈的大小等;
也就引出了yeild和resume这两个功能

[*]yeild的中文名叫让出,cpu每个时刻只能运行一个操作(),让出操作会让当前cpu的寄存器空出给其他协程运行体(函数)使用
[*]resume的中文名叫恢复,cpu空出后,恢复之前协程运行体(函数)执行的位置。
由于讨论的是一个线程的操作,不会出现内核切换线程的操作。
接下来要说是调度器,使用yeild和resume两个操作,进行切换协程。使用协程A->调度器->协程B这种形式的切换,而不是协程A->协程B。下图可以很好说明这个形式。

协程状态检测

协程调度器在调度协程运行体的时候就需要维护协程所具有的状态,比如就绪、等待、睡眠。
这也就需要一些数据结构进行维护这些运行体。

[*]就绪状态由于这些运行体不需要设置优先级,就可以使用队列先进先出的性质;
[*]睡眠一定会有过期时间,就可以使用定时器相关的数据结构,比如红黑树、最小堆等。
[*]等待IO准备也是有时间的,同睡眠状态一样,使用相同的数据结构
总结


[*]协程是针对同步IO处理的一个组件,让同步逻辑的代码有着异步的效率;
[*]利用IO阻塞的时间,去处理其他的事情。但是你要说它是异步也不对,它的整体代码逻辑是串行的;
[*]协程是由运行体和调度器组成;
[*]运行在一个线程上,针对于服务器开发,不需要为每一个客户端连接的IO创建一个线程(这种方法本身就是不对的,因为有上万个客户端,不能也创建上万个线程,对吧),让这个度比使用线程更小。
扩展

至于它和reactor进行对比,它俩的性能差距不会很大。
协程相比于reactor,reactor的回调函数太过于分散,不易代码可读。
reactor其实是对事件进行一个异步的处理,于此同时也不需要看到IO处理的逻辑,只需要关注每一个事件应该怎么做。

来源:https://www.cnblogs.com/zqurgy/p/17438624.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 协程概述讲解