关于IO,同步/异步/阻塞/非阻塞,这几个关键词是经常听到的,譬如:

“Java oio是阻塞的,nio是非阻塞的”

“NodeJS的IO是异步的”

但是这些东西听多了就容易迷糊,比方说同步是否就是阻塞,异步是否就是非阻塞呢?

先给出结论:

1. 异步/同步与阻塞/非阻塞之间没有必然的联系

2. 同步IO可以是阻塞,也可以是非阻塞的

3. 异步IO就是异步IO,它一定是非阻塞的,不存在异步阻塞IO这个说法

POSIX对同步/异步的定义如下,这两句话非常关键

- A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;
- An asynchronous I/O operation does not cause the requesting process to be blocked;

再给出权威文档:《UNIX网络编程:卷一》的第六章

书中列出了如下五种IO模型:

  • 阻塞式I/O;

  • 非阻塞式I/O;

  • I/O复用(select,poll,epoll...);

  • 信号驱动式I/O(SIGIO);

  • 异步I/O(POSIX的aio_系列函数);

1. 阻塞式IO

我们手上有一个socket,现在希望能从这个socket里读点数据出来,我们会对这个socket调用recvfrom方法

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
  struct sockaddr *src_addr, socklen_t *addrlen);

在默认情况下,recvfrom方法会被阻塞,直到从指定的socket上收到数据才会返回,返回时,buf中已经填充好了数据

阻塞的过程实际上可以分割成两段:等待kernel准备好从网络上接收到的数据报 + 等待收到的报文被从kernel复制到buf中

只有在这两个过程全部完成后,recvfrom方法才会返回。

这就是阻塞式IO模型

2. 非阻塞式IO

还是上面的recvfrom方法,如果将其设置为非阻塞模式(flag与MSG_DONTWAIT异或),情况就会有所不同了:

在内核没有准备好数据报时,调用recvfrom方法会立即返回异常码(EWOULDBLOCK或者EAGAIN)(这一段是非阻塞的!)

如果内核已经准备好数据,调用recvfrom方法则会在数据报被从kernel拷贝到buf中后返回(这一段是同步的!)

也就是说,阻塞与非阻塞式IO的主要区别在于等待数据报准备好的第一阶段,至于将数据从kernel拷贝到buf中的过程,两者都是同步的。

但是个人觉得非阻塞式IO可能并不好用,因为在轮询一个socket是否可读的过程会直接占满一个core

如果想要减少cpu资源占用的话,又会增加编程的复杂度。

3. I/O多路复用

IO多路复用有select/poll/epoll这样的几种方式

先介绍一下最有代表性的select方法

int select(int nfds, fd_set *restrict readfds,
  fd_set *restrict writefds, fd_set *restrict errorfds,
  struct timeval *restrict timeout);

select方法的返回值代表当前可以操作的fd数量,如果返回值大于0,说明已经有fd准备就绪,下一步我们就可以调用recvfrom方法从就绪的fd中读取数据了(先只考虑可读的情况)

select方法是否阻塞,与timeout参数有关

如果timeout被设置为0,那么select是非阻塞的,对select方法的调用会立即返回。

如果timeout被设置为非0,则select会阻塞,直到有fd可读,或者timeout到期为止。

总的来说,I/O多路复用是同步阻塞的,但主要是阻塞在对select/poll/epoll方法的调用上,后续的recvfrom则是同步的。

多说一句,I/O多路复用,实际上跟第一条介绍的阻塞IO差不多
只是I/O多路复用可以同时监听多个fd罢了

这样就减少了为每个需要监听的fd开启一个线程的开销。

4. 信号驱动式I/O

没用过也没见过,直接上截图:

5. 异步I/O

同步IO中,在调用recvfrom方法时,即使kernel已经将数据准备好,recvfrom方法也不会立即返回

必须要在耗费一定的时间,将数据从kernel完全拷贝到用户buf中后,recvfrom方法才会返回

也就是说,在recvfrom方法无异常返回的时候,数据已经在buf中准备好了

异步IO则有相当大的不同:

1. 用户调用一次请求数据的方法,该方法会无阻塞的立即返回。

2. OS接到这个请求后,会将用户所请求的数据从kernel拷贝到指定的位置。

3. 数据拷贝完成后,第一步中注册的回调方法会被调用(或者触发一个信号,总之就是要让用户感知到数据已经拷贝完成)

4. 用户感知到这一事件,此时数据已经准备好,可以直接处理数据了

如下图所示

但是目前Linux的aio还不成熟,而且epoll提供的IO多路复用模型在性能上已经够用了,所以在此就不举例了

ps. NodeJS在Linux上的异步实现是基于libeio,这是用阻塞IO和线程池模拟出来的异步IO

最后上一张图作为总结

最后再把文章开头的两句话再重复一遍,理解想必会更加深刻

- A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;
- An asynchronous I/O operation does not cause the requesting process to be blocked;

参考文献

网络编程释疑之:同步,异步,阻塞,非阻塞

Java IO 学习(一)同步/异步/阻塞/非阻塞的更多相关文章

  1. tornado 学习笔记4 异步以及非阻塞的I/O

    Read-time(实时)的网站需要针对每个用户保持长时间的连接.在传统的同步网站服务中,通常针对每个用户开启来一个线程来实现,但是这样做非常昂贵. 为了使并发连接的成本最小化,Tornada使用单个 ...

  2. JAVA NIO学习三:NIO 的非阻塞式网络通信

    紧接着上一章,我们继续来研究NIO,上一章中我们讲了NIO 中最常见的操作即文件通道的操作,但实际上NIO的主要用途还是在于网络通信,那么这个时候就会涉及到选择器,这一章我们就会对其进行讲解操作. 一 ...

  3. 【转载】高性能IO设计 & Java NIO & 同步/异步 阻塞/非阻塞 Reactor/Proactor

    开始准备看Java NIO的,这篇文章:http://xly1981.iteye.com/blog/1735862 里面提到了这篇文章 http://xmuzyq.iteye.com/blog/783 ...

  4. 谈谈对不同I/O模型的理解 (阻塞/非阻塞IO,同步/异步IO)

    一.关于I/O模型的问题 最近通过对ucore操作系统的学习,让我打开了操作系统内核这一黑盒子,与之前所学知识结合起来,解答了长久以来困扰我的关于I/O的一些问题. 1. 为什么redis能以单工作线 ...

  5. 高性能IO设计模式之阻塞/非阻塞,同步/异步解析

    提到高性能,我想大家都喜欢这个,今天我们就主要来弄明白在高性能的I/O设计中的几个关键概念,做任何事最重要的第一步就是要把概念弄的清晰无误不是么?在这里就是:阻塞,非阻塞,同步,异步. OK, 现在来 ...

  6. JAVA 中BIO,NIO,AIO的理解以及 同步 异步 阻塞 非阻塞

    在高性能的IO体系设计中,有几个名词概念常常会使我们感到迷惑不解.具体如下: 序号 问题 1 什么是同步? 2 什么是异步? 3 什么是阻塞? 4 什么是非阻塞? 5 什么是同步阻塞? 6 什么是同步 ...

  7. linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO(转载)

      IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file ...

  8. 理解同步,异步,阻塞,非阻塞,多路复用,事件驱动IO

    以下是IO的一个基本过程 先理解一下用户空间和内核空间,系统为了保护内核数据,会将寻址空间分为用户空间和内核空间,32位机器为例,高1G字节作为内核空间,低3G字节作为用户空间.当用户程序读取数据的时 ...

  9. 关于IO的同步,异步,阻塞,非阻塞

    上次写了一篇文章:Unix IO 模型学习.恰巧在这次周会的时候,@fp1203 (goldendoc成员之一) 正好在讲解poll和epoll的底层实现.中途正好讨论了网络IO的同步.异步.阻塞.非 ...

随机推荐

  1. VScode的settings.json配置

    { "editor.mouseWheelZoom": true, "astyle.additional_languages": [ "c", ...

  2. 最小生成树:HDU1863-畅通工程

    畅通工程 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submissi ...

  3. OpenStack之虚机热迁移代码解析

    OpenStack之虚机热迁移代码解析 话说虚机迁移分为冷迁移以及热迁移,所谓热迁移用度娘的话说即是:热迁移(Live Migration,又叫动态迁移.实时迁移),即虚机保存/恢复(Save/Res ...

  4. Android SDK 目录详解(转)

    Android SDK目录结构和工具介绍是本文要介绍的内容,主要是来了解并学习Android SDK的内容,具体关于Android SDK内容的详解来看本文. Android SDK目录下有很多文件夹 ...

  5. Python中@property和@classmethod和@staticmethod

    前戏 首先,先要弄清楚一个类里面的,各个组成部分都应该怎么称呼. - 注:可能叫法会不太一样. 关于@property 顾名思义:它的意思为‘属性’. 作用: 1:使用它你将会把类方法,变为类属性.并 ...

  6. ROM+VGA 图片显示

    内容 1.将一幅图片制成mif文件,初始化rom,图片像素为 120 * 60 2.驱动VGA,将图片显示在屏幕上 1.VGA 时序 下面是我的笔记截图,感觉更好理解. 2.640*480 60hz ...

  7. js后台提交成功后 关闭当前页 并刷新父窗体(转)

    原文地址:http://www.cnblogs.com/chenghu/p/3696433.html 后台提交成功后 关闭当前页 并刷新父窗体 this.ClientScript.RegisterSt ...

  8. UVALive 5987

    求第n个数,该数满足至少由3个不同的素数的乘机组成 #include #include #include #include #include using namespace std; int prim ...

  9. mysql-Innodb事务隔离级别-repeatable read详解

    http://blog.csdn.net/dong976209075/article/details/8802778 经验总结: Python使用MySQLdb数据库后,如使用多线程,每个线程创建一个 ...

  10. HTML5 新增绘图功能

    <!DOCTYPE html> <html> <head lang="en"> <title></title> < ...