zoukankan      html  css  js  c++  java
  • 4个常见的IO模型——阻塞、非阻塞、多路复用、异步

    在Unix网络编程中,史蒂文斯给出了5种IO编程模型,其中最重点、也最常用的是多路复用模型(Multiplexing)。
    这5种模型分别为:

    • 阻塞式IO
    • 非阻塞式IO
    • IO多路复用(multiplexing io),基于select/poll/epoll
    • 信号驱动式IO SIGIO
    • 异步IO(posix aio_abi和libaio)

    想要说明清楚这几个模型,一个很好的方式是把网络IO分为两个阶段来理解。第一阶段,从客户端向服务端发送请求开始,到数据从网络传输到达,完全准备好为止。第二阶段,数据从内核空间复制到程序缓存(即用户空间),这个阶段才是应用真正执行recvfrom系统调用的阶段。在第一阶段,程序要么阻塞在recvfrom调用上,要么阻塞在select之类的方法上,或者干其他的事情去了(轮询、异步等)。

    有了这个基本认知,我们再来逐个审视这几种模型。

    阻塞式I/O模型

    阻塞式IO(blocking I/O)是最基本的IO模型,也是日常使用中默认的模式。

    如上图,应用发出请求,试图执行recvfrom系统调用,以获取数据,由于数据还没准备好(也许服务端才开始处理请求),当前请求线程被阻塞,只能傻傻的等待,直到数据可读或者抛出异常。如果是单线程应用,主线程挂起,CPU空置。如果是多线程,当前线程挂起,CPU切换时间片去执行其他线程。

    非阻塞式IO模型

    一般的Socket对象都会有一个setblocking(False)或者ConfigureBlocing(false)之类的方法,将当前IO线程设置成非阻塞模式。

    如图,当socket设置为nonblocking时,在一阶段(数据准备阶段,还记得前面说的二阶段IO么,这里派上了用场)线程会不断的发起recvfrom轮询,如果还没有准备好数据,会得到一个EWouldBLOCK错误信号,直到数据准备好之后,开始真正执行recvfrom拉取数据。轮询会极大的消耗CPU时间,所以这种模型极少用到。

    IO多路复用

    I/O复用,即I/O multiplexing,这是一种基于select函数的编程模型,也是最常用的一种。有些人喜欢把它称作异步阻塞模型,我觉得这种叫法很容易让人产生误解,实际上这个模型和所谓的异步I/O没有半毛钱关系。

    如上图,在第一阶段,我们可以通过select函数注册多路IO对象。每一个注册的IO对象都会阻塞在select函数上,直到IO对象的状态发生改变。此时数据已经准备好读/写。调度器遍历这些IO对象,返回准备好读/写的IO对象。紧接着进入第二阶段,开始对准备好的IO对象调用recvfrom函数。

    对于多路复用模型,Java NIO基于select库实现了调度器Selector,python的selectors模块分别提供了基于selectpoll以及epoll库的封装对象。

    通过以上过程,我们还可以看到,其实IO多路复用阻塞IO很相似,基本两个阶段都在阻塞状态。只不过前者第一阶段阻塞在select函数上,第二阶段阻塞在recvfrom调用上;而后者全程阻塞在recvfrom上。而且IO多路复用由于需要注册、遍历IO对象,其实涉及到更多的步骤开销。但是多路复用的优势正在于可以同时对接多个IO对象,结合多线程技术,可以带来很大的灵活性。

    异步IO模型

    前面提到的三种模型,本质上在真正的IO阶段(第二阶段),都会阻塞。而在异步IO模型中,应用发出数据请求后,不再等待,直接返回。期间线程也不会阻塞。之后由内核处理两个阶段IO,然后给应用发送信号,程序直接获取数据。

    基于Unix系统有一个POSIX异步IO库——aio_abi,以及一个第三方库aiolib,后者可能更加知名。异步IO模型非常复杂,一般很少见到。另外我也有一些疑惑,python中的asyncio包提出的协程概念,和这里的异步IO是否为同一件事物。史蒂文斯在这里描述的异步明显需要基于系统内核的相关实现,和asyncio这种单纯的编程概念,大概说的不是一个层级的东西吧。

    隐喻

    最后还是说一个比喻吧。如果把IO模型比作网购,在你提交订单的一刻到快递员将货物带到你家小区门口期间,可看作一阶段IO。之后小哥给你打电话:“你的快递,快开门”,这相当于数据准备好了,并发送了通知。之后,你跑到门口将快递一件一件搬到家里,这是第二阶段。

    阻塞模型相当于你提了订单,就不吃不喝,只等着快递,直到小哥给你打电话,然后吭哧吭哧把快递搬到家,你才开始吃喝、睡觉等。非阻塞模型下,你提交订单后就开始自由行动了。但是仍然会每隔几分钟跑到小区门口看看快递到了没(轮询),一直把自己搞得精疲力尽。直到小哥给你打电话,你把快递搬回家才算消停。多路复用模型下,你同时提交了多个订单,但不再傻傻的朝门口来回跑了,而是紧紧盯着菜鸟裹裹信息(阻塞在select),直到其上显示至少有一个快递到了,你会嗖的跑过去,当然,快递仍然自己搬(recvfrom阻塞)。异步模型下,你雇了一个万能管家吉福斯,你只要下完订单,就不用操心了,他会打点好一切,最后他会把快递按照你们约定的地点、方式,直接送到你的手上。

    我变秃了,但是没变强
  • 相关阅读:
    SAP MM 采购附加费计入物料成本之二
    SAP MM 采购附加费计入物料成本?
    SAP MM 作为采购附加费的运费为啥没能在收货的时候计入物料成本?
    SAP MM 外部采购流程里的Advanced Return Management
    SAP MM 外部采购流程里的如同鸡肋一样的Advanced Returns Management功能
    SAP MM Why is the freight not included in the material cost at the time of GR?
    SAP MM: Change of material moving average price after goods receipt and invoice verification posting for PO
    SAP 创建启用了ARM功能的采购订单,报错 Shipping processing is not selected to supplier 100057 in purchase org. 0002
    GIT·代码仓库默认分支更改
    .Net/C#·运行报错缺少XXX文件,但双击无法跳转缺少位置
  • 原文地址:https://www.cnblogs.com/Franken-Fran/p/io_model.html
Copyright © 2011-2022 走看看