协程和IO多路复用

IO操作

当一个文件读操作发生时:

  1. 等待数据拷贝到内核缓冲区(比如加载文件、等待完整的UDP包)
  2. 将数据从内核拷贝到进程
IO多路复用和协程

传统的网络编程使用多线程模型,一个监听socket,然后每来一个请求就多线程开启一个新的会话socket。由于多线程的理论并发上限是CPU的核心数,当并发量越来越大的时候,就会有大量的线程处于就绪态等待执行,并且会存在频繁的线程上下文切换(线程栈、栈指针等寄存器),从而影响真正执行业务代码的时间。

  • IO多路复用

之前程序在进行IO操作时,主要有阻塞式和非阻塞式两种方式。当读缓冲区为空或写缓冲区满了的时候,阻塞式的运行状态将变为阻塞态,让出CPU;非阻塞态则以“忙等待”的方式检查就绪

IO多路复用由OS提供支持,一次系统调用能够同时监听多个socket

  • 协程

协程,又被称为用户态线程,是对线程的更细粒度的划分。相当于在线程的地址空间中,用户主动地去分配协程执行栈,并由用户自行调度。整个过程对OS隐身,在OS看起来只是一个线程在运行,即所谓“用户态线程”。

为什么协程切换的代价比线程低

协程调度的时候,也需要进行现场的切换,比如协程ID、执行栈的位置。

比起线程切换,协程切换“轻量”之处在于:

  1. 线程切换开销更大。除了寄存器上下文,线程还需要进行优先级、内核态进出等等更多的业务逻辑。
  2. 协程的切换次数比线程少很多。协程一般在达到了IO之类的阻塞点时切换(或用户主动yield);线程的切换是由OS调度的,不仅在IO时切换,时间片一到也会被切换。从这个角度来看,协程更适合IO密集型的程序,而多线程/多进程适合计算密集型的程序(可以充分利用多核)。
  • 协程+IO多路复用

IO多路复用可以同时监测好几个描述符,但是也存在频繁保护和恢复描述符现场的问题。可以用协程来解决,监听fd就绪之后,创建一个新的fd,交给协程来处理,这样相关现场保护就可以交由协程完成。

EPOLL/POLL/SELECT
  • select

设置一个监听描述符集,和一个超时时间,当存在准备好的描述符或者达到超时时间就返回。

缺点

  1. 描述符集用16个unsigned long来表示,最多支持16*64个并发
  2. 每次select需要传递所有监听集合,带来频繁的用户态到内核态拷贝数据
  3. 每次需要遍历整个监听集合
  • poll

和select类似,但是用一个pollfd指针来表示描述符集。没有最大数量限制。

  • epoll

提供三个接口:

epoll_create1用于创建一个epoll;

epoll_ctl用于添加、修改、删除一个监听的描述符

epoll_wait可以获取就绪的描述符集合

reference

为什么协程切换的代价比线程切换低?

go网络io模型分析

协程和IO多路复用

Linux IO模式及 select、poll、epoll详解

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值