zoukankan      html  css  js  c++  java
  • 刨根问底拦不住——I/O模型

    前言

    看过很多资料,很多对I/O模型概念模糊甚至错误,希望这篇文章有助理解I/O,欢迎讨论和纠正

    参考资料:《UNIX网络编程卷1》  P122

    I/O中涉及概念

    介绍阻塞非阻塞,同步异步之前,先分析一下I/O请求过程

    1. 等待数据准备好
    2. 从内核向进程复制数据

    过程1决定是否阻塞,过程2决定是否同步

    误区1:不要以为是否阻塞和是否同步会排列组合成4中状态,实际上只有三种:同步阻塞,同步非阻塞,异步非阻塞(一般来说异步非阻塞就成为异步,都异步了还阻塞啥?很多资料竟然还扯异步阻塞)

    那么究竟什么是同步异步,阻塞非阻塞?

    同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)

    所谓同步,就是在发出一个*调用*时,在没有得到结果之前,该*调用*就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由*调用者*主动等待这个*调用*的结果。

    而异步则是相反,*调用*在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在*调用*发出后,*被调用者*通过状态、通知来通知调用者,或通过回调函数处理这个调用。

    阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态

    阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。

    非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

    总结

    同步和异步说的是消息通知机制:同步的情况下,是由处理消息者自己去等待消息是否被触发,而异步的情况下是由触发机制来通知处理消息者

    阻塞非阻塞说的是消息处理机制:

    Unix可用的5中I/O模型:

    • 阻塞式I/O
    • 非阻塞式I/O
    • I/O复用(select和poll)
    • 信号驱动式I/O(SIGIO)
    • 异步I/O(POSIX的aio_系列函数)

    生活中的例子

    我经常和同学去吃庆丰包子,从点餐开始就出现了I/O模型

    我:应用程序

    前台:内核

    点餐:I/O请求

    阻塞式I/O:我去前台点餐(I/O请求),点玩后站那毛都不干(等待数据,进程sleep),于此同时前台让后厨准备包子,后厨做好后给前台(数据准备好),我端着盘子去找位置坐下(复制数据)

    非阻塞式I/O:我去前台点餐(I/O请求),点玩后站在那里无聊,就和朋友打电话(等待数据但进程没有sleep),但眼睛还是时不时扫一眼看看包子好没好(轮询内核),于此同时前台让后厨准备包子,后厨做好后给前台(数据准备好),我端着盘子去找位置坐下(复制数据)

    I/O复用(select和poll):班里组织吃包子,4人一桌,班长说各位落座,我自己在前台等着通知大家,班长记录了一个纸条,上面是对应的桌子和点的餐(描述符集合),他在前台等着谁的包子做好了就叫谁,被叫到的同学端着盘子回到座位(复制数据)

    信号驱动式I/O:事实上这种才是庆丰包子铺的做法,我我去前台点餐(I/O请求),服务员给我一个号码,然后我落座跟同学吹牛逼,一会服务员叫到38号你的包子好了(信号),我就屁颠屁颠跑到前台把包子端回来(复制数据)

    异步I/O:(POSIX的aio_系列函数):由于常去庆丰吃包子,我成为了VIP用户。这天我去前台点餐(I/O请求),然后我落座跟同学吹牛逼,吹到一半包子好了,但是服务员也没叫我(事实上我都不知道包子好了这件事),我还在继续吹牛逼,服务员这时把包子端上来了(复制数据由内核完成了)。这实际上是饭点常用的做法

    总结:等待包子做好的过程是等待数据,等待过程中你是挂起还是搞基(是否sleep)决定了是否阻塞;包子准备好了,是你自己去取还是让服务员给你拿来决定了是否是异步,事实上如果你选择让服务员给你拿来(异步),也就没必要看着盯着前台看看包子是否做好了,因为你不用关心是否做好了(因为好了后服务员给你拿过来),从这个角度去思考就知道为什么没有异步阻塞了

    陈硕在知乎上的回答也印证了这一点:

    阻塞式I/O

     

    默认情况下,所有套接字都是阻塞的。从调用recvfrom开始到它返回的整段时间内是被阻塞的。recvfrom成功返回后,应用进程开始处理数据报

    非阻塞式I/O

    I/O复用(select和poll)

    信号驱动式I/O(SIGIO)

    这种模型的优势在于等待数据报到达期间进程不被阻塞,主循环可以继续执行

    异步I/O

    信号驱动式I/O是由内核通知我们何时可以启动一个I/O操作,而异步I/O模型是由内核通知我们I/O操作何时完成

    I/O模型比较

    同步I/O操作:导致请求进程阻塞,直到I/O操作完成

    异步I/O操作:不导致请求进程阻塞

    前四种模型的主要区别在第一阶段,因为它们第二阶段是一样的:在数据从内核复制到调用者的缓冲区期间,进程阻塞于recvfrom调用

    异步I/O模型在这两个阶段都要处理,前四种都是同步,因为其中真正的I/O操作(recvfrom)将阻塞进程。只有异步I/O模型与POSIX定义的异步I/O相匹配

    其它好的博客;

    也谈同步异步I/O

    select、poll、epoll之间的区别总结

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

    可能是最接地气的 I/O 多路复用小结

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

  • 相关阅读:
    「题解」洛谷 P1731 [NOI1999]生日蛋糕
    「题解」洛谷 P1063 能量项链
    Log4j2笔记
    基数排序
    会计知识
    归并排序
    CF668 题解
    拉格朗日反演
    [国家集训队]数颜色 / 维护队列 「带修莫队」
    简单的填数「贪心」
  • 原文地址:https://www.cnblogs.com/raichen/p/5722457.html
Copyright © 2011-2022 走看看