请求描述:

`阻塞/非阻塞` 和 `同步/异步` 不是一个概念。举几个简单的例子。

当进程调用一个进行IO操作的API时(比如read函数),在数据没有到达前,read 会挂起,进程会卡住。在数据读取完毕返回给进程时,

      read 返回(返回值为读取到的字节数,数据从内核拷贝到用户空间),然后进程继续执行。那么这次 read 调用,是阻塞的。

非阻塞就是 read 在数据没有读取完毕前,就返回了(返回值为-1,errno 设置为 EAGAIN)。此时进程没有拿到需要的数据。那怎么办?

 
 
有两种办法。

一种是同步

因为进程没办法知道数据什么时候才真正读取完毕了,所以需要每隔一段时间就去轮询一下(就是重新调用 read,看是不是数据真的已经读取完毕了)。

   大部分场景中都不会使用这种方式。但在某些特殊的情况下效率会特别高。

一种是异步:

早期的异步实现方式是内核给进程发信号(SIGIO 或者 SIGPOLL)。数据读写完毕后,内核发信号给进程,然后进程内的信号处理函数再调用 read 读取数据(这时可以确保数据真的已经读取完毕了)。但这种方式有一个小小的瑕疵,就是在进程进行多个 fd 读写的时候,信号来的时候没办法分清到底是哪个 fd 上的数据已经真正准备好了。所以进程还是要对所有持有的 fd 进行 read 调用。
    后来的异步实现,就有了更好的 select / poll / epoll(I/O multiplexing)。现在基本上像比较流行的 Nginx / Redis 都用 epoll(在 FreeBSD 上是 kqueue)

 
 
 

图解:

阻塞式I/O模型:默认情况下,所有套接字都是阻塞的。怎么理解?先理解这么个流程,一个输入操作通常包括两个不同阶段:

(1)等待数据准备好;
(2)从内核向进程复制数据。

对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达。当所有等待分组到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用程序缓冲区。 好,下面我们以阻塞套接字的recvfrom的的调用图来说明阻塞

标红的这部分过程就是阻塞,直到阻塞结束recvfrom才能返回。

非阻塞式I/O: 以下这句话很重要:进程把一个套接字设置成非阻塞是在通知内核,当所请求的I/O操作非得把本进程投入睡眠才能完成时,

不要把进程投入睡眠,而是返回一个错误。看看非阻塞的套接字的recvfrom操作如何进行

可以看出recvfrom总是立即返回。

I/O多路复用:虽然I/O多路复用的函数也是阻塞的,但是其与以上两种还是有不同的,I/O多路复用是阻塞在select,epoll这样的系统调用之上,

而没有阻塞在真正的I/O系统调用如recvfrom之上。如图

信号驱动式I/O:用的很少,就不做讲解了。直接上图

异步I/O:这类函数的工作机制是告知内核启动某个操作,并让内核在整个操作(包括将数据从内核拷贝到用户空间)完成后通知我们。如图:

注意红线标记处说明在调用时就可以立马返回,等函数操作完成会通知我们

例子说明:

 例子一:
       一个网络包从应用程序A发到另一台电脑上的应用程序B,需要经历:
  1. 从A的业务代码到A的软件框架
  2. 从A的软件框架到计算机的操作系统内核
  3. 从A所在计算机的内核到网卡
  4. 从网卡经过网线发到交换机等设备,层层转发,到达B所在计算机的网卡
  5. 从B所在计算机的网卡到B所在计算机的内核
  6. 从B所在计算机的内核到B的程序的用户空间
  7. 从B的软件框架到B的业务代码

例子二:

小乐爱喝茶,废话不说,煮开水。
    出场人物:小乐,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
       1 小乐把水壶放到火上,立等水开。(同步阻塞)
         ——   小乐觉得自己有点傻
       2 小乐把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)
         ——  小乐还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出呜呜~~~~的噪音。
       3 小乐把响水壶放到火上,立等水开。(异步阻塞)
         ——  小乐觉得这样傻等意义不大
       4 小乐把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)
         ——  小乐觉得自己聪明了。

所谓同步异步,只是对于水壶而言。
     普通水壶,同步;响水壶,异步。
     虽然都能干活,但响水壶可以在自己完工之后,提示小乐水开了。这是普通水壶所不能及的。
     同步只能让调用者去轮询自己(情况2中),造成小乐效率的低下。

所谓阻塞非阻塞,仅仅对于小乐而言。
    —— 立等的小乐,阻塞;看电视的小乐,非阻塞。

情况1和情况3中小乐就是阻塞的,媳妇喊他都不知道。

虽然3中响水壶是异步的,可对于立等的小乐没有太大的意义。

所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。

阻塞式I/0 和 非阻塞式I/O 同步异步详细介绍的更多相关文章

  1. Linux设备驱动程序学习 高级字符驱动程序操作[阻塞型I/O和非阻塞I/O]【转】

    转自:http://blog.csdn.net/jacobywu/article/details/7475432 阻塞型I/O和非阻塞I/O 阻塞:休眠 非阻塞:异步通知 一 休眠 安全地进入休眠的两 ...

  2. 五种I/O 模式——阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/O

    五种I/O 模式——阻塞(默认IO模式),非阻塞(常用语管道),I/O多路复用(IO多路复用的应用场景),信号I/O,异步I/O 五种I/O 模式:[1]        阻塞 I/O          ...

  3. Linux非阻塞IO(四)非阻塞IO中connect的实现

    我们为客户端的编写再做一些工作. 这次我们使用非阻塞IO实现connect函数. int connect(int sockfd, const struct sockaddr *addr, sockle ...

  4. Linux非阻塞IO(三)非阻塞IO中缓冲区Buffer的实现

    本文我们来实现回射服务器的Buffer.   Buffer的实现   上节提到了非阻塞IO必须具备Buffer.再次将Buffer的设计描述一下: 这里必须补充一点,writeIndex指向空闲空间的 ...

  5. JAVA阻塞(IO)和非阻塞(NIO)

    查看这篇文章,了解更多关于Java的阻塞和非阻塞替代创建套接字的信息. 套接字使用TCP / IP传输协议,是两台主机之间的最后一块网络通信. 您通常不必处理它们,因为它们之上构建了协议,如HTTP或 ...

  6. Java基础——NIO(二)非阻塞式网络通信与NIO2新增类库

    一.NIO非阻塞式网络通信 1.阻塞与非阻塞的概念  传统的 IO 流都是阻塞式的.也就是说,当一个线程调用 read() 或 write() 时,该线程被阻塞,直到有一些数据被读取或写入,该线程在 ...

  7. Linux NIO 系列(03) 非阻塞式 IO

    目录 一.非阻塞式 IO 附:非阻塞式 IO 编程 Linux NIO 系列(03) 非阻塞式 IO Netty 系列目录(https://www.cnblogs.com/binarylei/p/10 ...

  8. 阻塞式和非阻塞式IO

    有很多人把阻塞认为是同步,把非阻塞认为是异步:个人认为这样是不准确的,当然从思想上可以这样类比,但方式是完全不同的,下面说说在JAVA里面阻塞IO和非阻塞IO的区别 在JDK1.4中引入了一个NIO的 ...

  9. NIO非阻塞式编程

    /** * NIO非阻塞式编程<p> * 服务端和客户端各自维护一个管理通道的对象,我们称之为selector,该对象能检测一个或多个通道 (channel) 上的事件. * 我们以服务端 ...

随机推荐

  1. django学习 session保持登录,且登出

    学一点记一点 刚刚进来的时候突然发现,博客园的主页在缩小的时候会发生一些挤压,有点意思 今天刚看了session,感觉之前太迷茫,把问题想得过于复杂了. 我这个是建立在有登录和注册的功能上的演示. 首 ...

  2. python面试的100题(14)

    32.请写出一个函数满足以下条件 该函数的输入是一个仅包含数字的list,输出一个新的list,其中每一个元素要满足以下条件: 1.该元素是偶数 2.该元素在原list中是在偶数的位置(index是偶 ...

  3. Android Studio3.0.0之前首次安装通用配置

    一.第一次安装: 温馨提示:在安装Android Studio之前,建议先提前准备好单独的Android SDK,这个可以在AndroidDevTools网站下载.以前用Eclipse做过Androi ...

  4. 组合数的计算以及组合数对p取余后结果的计算

    前奏:统计 n! 中的所有质因子中pi的个数 普通方法:复杂度O(nlogn), 当n为10的18次方无法承受 // 复杂度O(nlogn), n为10的18次方无法承受 int cal(int n, ...

  5. [BJWC2010] 外星联络 - 后缀数组

    [BJWC2010] 外星联络 Description 求一个 \(01\) 串中所有重复出现次数大于 \(1\) 的子串所出现的次数,按照字典序排序输出. Solution 预处理出后缀数组和高度数 ...

  6. 安装php-zbarcode的步骤方法

    1 安装ImageMagick依赖 yum install ImageMagick ImageMagick-devel 2 安装zbar拓展 wget -c http://jaist.dl.sourc ...

  7. web前端常用库

    项目中可能用到的web前端库(持续记录): 1.轻量化货币库:https://github.com/openexchangerates/accounting.js   ,美元形式.欧元形式等 2.时间 ...

  8. linux 创建svn版本库,并在svn上配置checkstyle做代码风格检查

    一.创建SVN版本库 1.安装svn服务器 yum install subversion 2.查看版本 svnserve --version 3.建立SVN版本库目录(即你的SVN服务器里面的文件存放 ...

  9. python3练习100题——009

    今天的题目好像有点水... 原题链接:http://www.runoob.com/python/python-exercise-example9.html 题目:暂停一秒输出. 我的代码: impor ...

  10. pyodbc 一些内容

    如果表格里是空的,读出来是会变为None,所以用是否等于None来判断内容是否为空.