关于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. Neon Lights in Hong Kong【香港霓虹灯】

    Neon Lights in Hong Kong Neon is to Hong Kong as red phone booths are to London and fog is to San Fr ...

  2. Java模拟音乐播放器 暂停与重新播放——线程如何控制另外一个线程的状态

    package com.example.Thread; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEve ...

  3. P2485 [SDOI2011]计算器

    P2485 [SDOI2011]计算器 题目描述 你被要求设计一个计算器完成以下三项任务: 1.给定y.z.p,计算y^z mod p 的值: 2.给定y.z.p,计算满足xy ≡z(mod p)的最 ...

  4. Java之OutOfMemoryError简单分析

    Java之OutOfMemoryError简单分析 最近编码遇到了Java内存溢出的问题,所以就想顺便总结一下几种导致Java内存溢出的栗子,以及碰到Java内存溢出要如何去解决. Java堆溢出 J ...

  5. uReplicator实现分析

    MirrorMakerWorker分析 是整个同步机制的主入口,主要组织的逻辑有: 配置数据的传入与处理,ConsumerConfig对象的构建 度量对象的准备,定时上报的度量数据收集线程的定义与启动 ...

  6. python - 接口自动化测试 - RunTest - 测试用例加载执行/测试报告生成

    # -*- coding:utf-8 -*- ''' @project: ApiAutoTest @author: Jimmy @file: run_test.py @ide: PyCharm Com ...

  7. 理解机器为什么可以学习(五)---Noise and Error

    之前我们讨论了VC Dimension,最终得到结论,如果我们的hypetheset的VC Dimension是有限的,并且有足够的资料,演算法能够找到一个hypethesis,它的Ein很低的话,那 ...

  8. [ZJOI2011][bzoj2229] 最小割 [最小割树]

    题面 传送门 思路 首先我们明确一点:这道题不是让你把$n^2$个最小割跑一遍[废话] 但是最小割过程是必要的,因为最小割并没有别的效率更高的算法(Stoer-Wagner之类的?) 那我们就要尽量找 ...

  9. linux压缩文件——解压方法

    linux下 tar解压 gz解压 bz2等各种解压文件使用方法 .tar 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName (注:tar ...

  10. git filter-branch应用

    1.修改author和committer git filter-branch --commit-filter ' export GIT_AUTHOR_EMAIL=me@example.com; exp ...