IO多路复用

IO多路复用

同步IO、异步IO、IO多路复用

IO两个阶段

  • IO过程分两阶段:
    1. 数据准备阶段。从设备读取数据到内核空间的缓冲区
    2. 内核空间复制回用户空间进程缓冲区阶段
  • 发生IO的时候:
    1. 内核从IO设备读数据(例如:淘米,把米放在饭锅里煮饭)
    2. 进程从内核复制数据(盛饭,从内核这个饭锅里把饭装到碗里来)
  • 系统调用----read函数

IO模型

同步IO模型包括阻塞IO非阻塞IOIO多路复用

  1. 阻塞IO:进程等待(阻塞),直到读写完成。(全程等待)
    system_002
    中文版
    system_003

  2. 非阻塞IO

    • 进程调用recvfrom操作,如果IO设备没有准备好,立即返回ERROR,进程不阻塞。用户可以再次发起系统调用(可以轮询),如果内核已经准备好,就阻塞,然后复制数据到用户空间。
    1. 第一阶段数据没有准备好,可以先忙别的,等会再来看看。检查数据是否准备好了的过程是非阻塞的。
    2. 第二阶段是阻塞的,即内核空间和用户空间之间复制数据时阻塞的。
    • 生活中的例子:淘米、蒸饭我不等,我去玩会,盛饭过程我等着你装好饭,但是要等到盛好饭才算完事,这是同步的,结果就是盛好饭。
      system_004
      中文版
      system_005
  3. IO多路复用

    • IO多路复用,也称为:Event-driven IO
    • 所谓IO多路复用,就是同时监控多个IO,有一个准备好了,就不需要继续等待其他IO,可以开始处理,提交了同时处理IO的能力。
    • select几乎所有操作系统平台都支持,poll是对select的升级。
    • epoll,Linux系统内核2.5+开始支持,对select和poll的增强,在监视的基础上,增加回调机制。BSD、Mac平台有kqueue,windows server有iocp。
      system_006
    • 以select为例,将关注的IO操作告诉select函数并调用,进程阻塞,内核“监视”select关注的文件描述符fd,被关注的任何一个fd对应的IO准备好了数据,select返回。再使用read将数据复制到用户进程。
    • select举例:食堂供应很多菜(众多的IO),你需要吃某三菜一汤,大师傅(操作系统)所要现做,需要等待,你只好等待大师傅叫。其中一样菜好了,大师傅叫你,说你点的菜有好的了,你得自己遍历找找看哪一样才好了,请服务员把做好的菜打给你。
    • epoll是有菜准备好了,大师傅叫你去几号窗口直接打菜,不用自己找菜了。
    • 一般情况下,select最多能监听1024个fd(文件描述符,监听数量可以修改,但不建议修改),但是由于select采用轮询的方式,当管理的IO多了,每次都要遍历全部fd,效率低下。
    • epoll没有管理的fd的上限,且是回调机制,不需遍历,效率很高。
      system_007
  4. 信号驱动IO

    • 进程在IO访问时,先通过sigaction系统调用,提交一个信号处理函数,立即返回。
    • 进程不阻塞。当内核准备好数据后,产生一个SIGIO信号(电平触发)并投递给信号处理函数。可以在此函数中调用recvfrom函数操作数据从内核控件复制到用户控件,这段过程进程阻塞。
      system_008
  5. 异步IO

    • 在进程发起异步IO请求,立即返回。内核完成IO的两个阶段,内核给进程发一个信号。
    • 举例:来打饭,跟大师傅说饭好了叫你,饭菜准备好了,窗口服务员把饭盛好了打电话叫你。两个阶段都是异步的。整个过程中,进程都可以忙别的,等好了才过来。
    • 举例:今天不想出去到饭店吃饭了,点外卖,饭菜在饭店做好了(第一阶段),快递员从饭店送到你家门口(第二阶段)。
    • Linux的aio的系统调用,内核从版本2.6开始支持
      system_009
      对应的中文版
      system_010
  • 总结
    前面4个都是同步IO,因为核心操作recv函数调用时,进程阻塞直到拿到最终结果为止,而异步IO进程全程不阻塞。
    system_011

Python中IO多路复用

  1. IO多路复用
    • 大多数操作系统都支持select和poll
    • Linux2.5+支持epoll
    • BSD、Mac支持kqueue
    • Solaris实现了/dev/poll
    • Windows server的IOCP
  • Python的select库实现了select、poll系统调用,这个基本上操作系统都支持。部分实现了epoll。它是底层的IO多路复用模块。
  • 开发中的选择
    1. 完全跨平台,使用select、poll。但是性能较差
    2. 针对不同操作系统自行选择支持的技术,这样做会提高IO处理的性能
  • select维护一个文件描述数据结构,单个进程使用有上限,通常是1024,线性扫描这个数据结构。效率低。
  • pool和select的区别是内部数据结构使用链表,没有这个最大限制,但是依然是线性遍历才知道那个设备就绪了。
  • epoll使用事件通知机制,使用回调机制提高效率
  • select/poll还要从内核空间复制消息到用户空间,而epoll通过内核空间和用户空间共享一块内存来减少复制。

selectors库

3.4版本提供selectors库,高级IO复用库。

  1. 层次结构:
    • BaseSelector
      • SelectSelector #实现select
      • PollSelector #实现poll
      • EpollSelector #实现epoll
      • DevpollSelector #实现devpoll
      • KqueueSelector #实现kqueue
  • selectors.DefaultSelector返回当前平台最有效、性能最高的实现。但是,由于没有实现Windows下的IOCP,所以,Windows下只能退化为select。
# 在selects模块源码最下面有如下代码
# Choose the best implementation, roughly:
#    epoll|kqueue|devpoll > poll > select.
# select() also can't accept a FD > FD_SETSIZE (usually around 1024)
if 'KqueueSelector' in globals():
    DefaultSelector = KqueueSelector
elif 'EpollSelector' in globals():
    DefaultSelector = EpollSelector
elif 'DevpollSelector' in globals():
    DefaultSelector = DevpollSelector
elif 'PollSelector' in globals
  • 7
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值