关于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. Ralph W. Tyler【拉尔夫·泰勒】

    Ralph W. Tyler Anyone who cares about what schools and colleges teach and how their student learn wi ...

  2. C语言实例解析精粹学习笔记——44(冒泡排序)

    冒泡排序,从序列的最后一个元素与前一个元素比较大小,如果R[n-1]>R[n]则交换两个元素的位置(R[0]作为临时存放区)将最小的数据交换到R[1],第二次循环将第二小的数交换到R[2].通过 ...

  3. Hie with the Pie POJ - 3311

    Hie with the Pie POJ - 3311 The Pizazz Pizzeria prides itself in delivering pizzas to its customers ...

  4. HDU 5971 二分图判定

    Wrestling Match Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  5. HOJ 13845 Atomic Computer有向无环图的动态规划

    考虑任意一个数字,任何一个都会有奇怪的..性质,就是一个可以保证不重复的方案——直接简单粗暴的最高位加数字..于是,如同上面的那个题:+1.-1.0 但是考虑到65536KB的标准内存限制,会得出一个 ...

  6. hibernate实体xml一对多关系映射

    单向一对多关系映射: 一个房间对应多个使用者,也就是Room實例知道User實例的存在,而User實例則沒有意識到Room實例. 用户表: package onlyfun.caterpillar; p ...

  7. C语言用一维数组打印杨辉三角(原:无意中想到)

    本贴地址 ] = { }; a[] = , a[] = ; int i, j,m; ; i <= ; i++) //2-11 输出10行 { ; j > ; j--) //关键在这句,倒着 ...

  8. mysql sum聚合函数和if()函授的联合使用

    今天去面试遇到一个数据库试题,首先说一下表结构如下: 表结构:mytest 表数据:mytest 要查询的结果如下: 在本题目中,需要用到sum聚合函数和if函数 sql如下: ,)) ,)) AS ...

  9. 【Plus One】cpp

    题目: Given a non-negative number represented as an array of digits, plus one to the number. The digit ...

  10. Wordpress 作者模板页中的自定义帖子类型分页问题

    <?php // 获取当前页面的页数,函数的参数为 paged $paged = (get_query_var('paged')) ? get_query_var('paged') : 1; $ ...