请求描述:

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

当进程调用一个进行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. How to do high impact research + 实事求是

    1. develop a strong publications record early, so do what you can to make that happen. 2. 粗读:abstrac ...

  2. 我的python笔记06

    面向对象学习 本节内容:   面向对象编程介绍 为什么要用面向对象进行开发? 面向对象的特性:封装.继承.多态 类.方法.     引子 你现在是一家游戏公司的开发人员,现在需要你开发一款叫做< ...

  3. 【转载】JS导出CSV文件

    转自:http://www.cnblogs.com/dengnan/p/3990211.html 通过自己实际测试有以下几种方法 方法一通过a标签实现,把要导出的数据用“\n”和“,”拼接成一个字符串 ...

  4. selenium爬去数据+存储

    1 爬去数据代码 #coding=utf-8 from selenium import webdriver from selenium.webdriver.common.by import By fr ...

  5. 《深入理解Java虚拟机》读书笔记六

    第七章 虚拟机类加载机制 1.类加载的时机 虚拟机的类加载机制: 虚拟机把描述类的数据从class文件中加载到内存,并对数据进行校验.转换解析和初始化,最终形成了可以被虚拟机直接使用的Java类型,这 ...

  6. SPDK-nvmf与不同传输类型的公共接口

    SPDK-nvmf与不同传输类型的公共接口 不同类型的传输层到nvmf的公共命令请求接口 nvmf_fc_hwqp_handle_request() -->cmd_iu = buffer-> ...

  7. 什么是kafka,怎么使用? (2) - 内含zookeeper等

    zookeeper依赖于java https://baike.baidu.com/item/yum/2835771?fr=aladdin http://yum.baseurl.org/ 去yum官网下 ...

  8. Codeforces Round #622 (Div. 2)C(单调栈,DP)

    构造出的结果一定是一个单峰/\这种样子的 #define HAVE_STRUCT_TIMESPEC #include<bits/stdc++.h> using namespace std; ...

  9. Weighted Visibility Graph With Complex Network Features in the Detection of Epilepsy

    Their data five data set, 100 single channel of EEG signals, each channel EEG has 4097 data point. t ...

  10. 【蓝桥杯/算法训练】Sticks 剪枝算法

    剪枝算法 大概理解是通过分析问题,发现一些判断条件,避免不必要的搜索.通常应用在DFS 和 BFS 搜索算法中:剪枝策略就是寻找过滤条件,提前减少不必要的搜索路径. 问题描述 George took ...