同事推荐,感觉写的不错就试着翻译了下.
原文链接: https://www.rubberducking.com/2018/05/the-various-kinds-of-io-blocking-non.html
作者: Didier A.

我发现对于软件程序员来说很难分清楚各种类型的IO.对于阻塞,非阻塞,多路复用和异步IO有很多的混淆点.
所以我想尝试解释清楚各种IO类型意味着什么

在硬件层面.

在现代操作系统中,IO(输入/输出)是一种和外围设备交换数据的方式.包括读写磁盘或SSD,通过网络发送和接受数据,在显示器上显示,接入键盘和鼠标输入,等等.

现代操作系统和外围设备的交流取决于外围设备的特定类型以及他们的固件版本和硬件能力.
通常来说,你可以认为外围设备是很高级的,他们可以同时处理多个并发的读写数据请求.也就是说,串行交流的日子一去不返了.
在这些场景中,外围设备和CPU间的交流在硬件层面都是异步的.

这个异步机制被称为硬件中断.
想想一个简单的场景,CPU请求外围设备去读取一些数据,接着CPU会进入一个无限循环,每一次都会检查外围设备的数据是否可用,直到获得了数据为止.
这种方法被称为轮询(polling),因为CPU需要保持检查外围设备.
在现代硬件中,取而代之发生的是CPU请求外围硬件执行操作,然后就忘了这件事,继续处理其他的CPU指令.只要外围设备做完了,他会通过电路中断来通知CPU.
这发生在硬件中,CPU因此不需要停下来或者检查这个外围设备,可以继续执行其他的工作,直到周边设备说已经做完了.

在软件层面

现在我们了解了硬件中发生的事,我们可以移动到软件这一侧了.
在这一层IO通过多种方式被暴露:阻塞,非阻塞,多路复用和异步.让我们一个个来仔细解释.

阻塞

还记得用户程序如何在一个进程内运行,代码是在线程的上下文中执行的吗?
你总是会遇到需要编写一个需要从文件中读取数据的程序的情况.
使用阻塞IO,你所做的是从你的线程中请求操作系统,将线程置于休眠(sleep),当数据可用于被消费时操作系统会唤醒线程.

也就是说,阻塞IO之所以被称为阻塞是因为使用他的线程会被阻塞直到IO完成.

非阻塞

阻塞IO的问题是当你的线程在休眠时,他除了等IO完成不能干其他事.
有时候,你的程序可能没有其他事可做了.
但如果还有其他事需要做的话,能在等待IO的时候并发做可是极好的.

其中一种实现方式被称为非阻塞IO.
他的思想是当你读取一个文件时,OS只是简单返回给你文件的内容或者一个等待状态告诉你IO还未完成,而不是将线程休眠.
他不会阻塞你的线程,但之后检查IO是否完成的工作还是交给了你.
这意味着当处于等待状态时,你可以去做一些工作,当你再次需要IO时,可以再读取一次,那时候IO可能已经完成了,文件的内容会返回,如果还是处于等待状态的话,你可以选择继续做其他事.

多路复用

非阻塞IO的问题是如果你在等待IO的过程中要做的其他事情就是另外的IO的话,事情会变得很奇怪.

在一个好的场景下,你请求OS去读取文件A的内容,然后去做一些重计算的工作,做完之后再去检查文件A是否完成读取,如果完成了,你再做一些关于这个文件内容的操作,不然就继续做其他的工作,循环往复.
但在一个坏的场景中,你没有重计算的工作要去做,而是需要去读取另一个文件B.
那除了等待他们还有什么事要做呢?
没有了,你的程序就进入了一个死循环,判断文件A是否被读取完毕,接着再去判断文件B,一遍又一遍.
要么你使用简单的状态轮询,这会导致过多消耗CPU,或者你手动加入一些随意的休眠时间,不过这也意味着你将延迟知道IO完成,这会降低程序的吞吐.

为了避免这个问题,你可以使用多路复用IO来代替.
他所做的是你再次阻塞在IO上,但这次不仅仅是一个一个的IO操作,你可以将所有需要的IO操作塞入队列,阻塞在所有的操作上. 当其中有一个IO完成之后OS会唤醒你.
一些多路复用的实现提供了更多的控制,你可以设置在特定一些IO操作完成之后再被唤醒,例如A和C文件或B和D文件完成的时候.

所有你可以调用非阻塞读取文件A,然后非阻塞读取文件B,最后告诉操作系统将我的线程置于休眠,当A和B的IO都完成的时候或其中一个完成的时候再唤醒他.

异步

多路复用IO的问题是在IO完毕前你还是处于休眠状态.
又一次,这对一些程序来说可行,那些除了等待IO操作完成外没有其他操作要去执行的程序.
但有时候,你确实需要去做其他事情.
可能你正在计算PI的数字,同时也在汇总一些文件的值.
你想要进行的操作是将所有的读操作入队列,当等待他们读取完成前,你可以继续计算PI.当一个文件读取完成后,你可以汇总他的值,然后继续进行PI的计算直到另一个文件完成读取.

为了让这可行,你需要一种方式当IO完成时中断PI的计算,并且你需要IO来执行这个操作当他完成时.

这通过事件回调完成.执行读操作的调用会需要一个回调,并且调用立即返回.当IO完成时,操作系统会挂起你的线程,并执行你的回调.当回调完成时,他会恢复你的线程.

多线程 vs 单线程?

你可能已经注意到我所描述的所有线程都是关于单个线程的,也就是你的主线程.
真相是,IO的执行不依赖于线程,这我在最开始就已经解释过了,外围设备都是在他们自己的电路里异步执行IO.
所以阻塞,非阻塞,多路复用和异步IO都是可能在单线程模型中被执行的.
这也是为什么并发IO可以不借助于多线程支持来工作.

现在,对于处理IO操作完成的结果,或者请求IO操作很明显是可以多线程的,如果你需要的话.这允许你在并发IO之上执行并发计算.所以没有什么东西阻止多线程和这些IO机制结合.

事实上,这里也有第五种受欢迎的基于多线程的IO.
他经常被混淆为非阻塞IO或异步IO,因为他对外暴露出的是类似他们的接口.
真相是,他是假装的非阻塞或异步IO.他的工作方式很简单,他使用阻塞IO,但是每个阻塞操作都是在他自己的线程中(注:多线程环境,非主线程中).
现在取决于他的实现机制,他要么接收一个回调,或者使用一种轮询模型,比如返回一个Future对象.

最后

我希望这篇文章可以帮助你澄清对多种IO的理解.还有很重要的一点需要注意,他们不是被所有的操作系统和所有的外围设备支持的.相似的,不是所有的编程语言都暴露了操作系统支持的所有IO类型的API.

这边请,所有类型的IO都解释了.

希望能对你有所帮助.

更多阅读

non-blocking IO vs async IO and implementation in Java

Asynchronous and non-blocking IO

Multiplexed I/O

Reactor pattern

Proactor pattern

There is no thread

Asynchronous I/O and event notification on linux

What is the status of POSIX asynchronous I/O (AIO)?

Kernel Asynchronous I/O (AIO) Support for Linux

I/O Completion Ports

免责声明

我不是一个系统层面的程序员,我也不是一个操作系统提供的所有种类IO方面的专家.这篇文章是我尽可能总结我所知的内容,更偏向于中间层面的知识.所以如果你发现有任何问题的话请指正我.

[翻译]各个类型的IO - 阻塞, 非阻塞,多路复用和异步的更多相关文章

  1. 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO

    同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出 ...

  2. 转 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO

    此文章为转载,如有侵权,请联系本人.转载出处,http://blog.chinaunix.net/uid-28458801-id-4464639.html 同步(synchronous) IO和异步( ...

  3. 操作系统介绍-操作系统历史,IO,进程的三态,同步异步阻塞非阻塞

    1.操作系统历史 2.进程,IO,同步异步阻塞非阻塞 操作系统历史: 手工操作: 1946年第一台计算机诞生--20世纪50年代中期,计算机工作还在采用手工操作方式.此时还没有操作系统的概念. 手工操 ...

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

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

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

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

  6. 阻塞IO、非阻塞IO的区别

    1.类与类之间的关系:依赖,实现,泛化(继承),关联,组合,聚合. 1)依赖(虚线):一个类是 另一个类的函数参数 或者 函数返回值. 2)实现(实线加小圆):对纯虚函数类(抽象类)的实现. 3)继承 ...

  7. 阻塞IO、非阻塞IO、同步IO、异步IO等

    https://www.cnblogs.com/zingp/p/6863170.html 阅读目录 1 基础知识回顾 2 I/O模式 3 事件驱动编程模型 4 select/poll/epoll的区别 ...

  8. python开发IO模型:阻塞&非阻塞&异步IO&多路复用&selectors

    一 IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非 ...

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

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

随机推荐

  1. 关于linux find命令的使用

    find 和 xargs   xargs和find 在 使用find命令的-exec选项处理匹配到的文件时, find命令将所有匹配到的文件一起传递给exec执行.但有些系统对能够传递给exec的命令 ...

  2. python之@property

    在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改: s = Student() s.score = 9999 这显然不合逻辑.为了限制score的 ...

  3. 科学计算工具Numpy

    参考学习资料: Python.NumPy和SciPy介绍:http://cs231n.github.io/python-numpy-tutorial NumPy和SciPy快速入门:https://d ...

  4. json & pickle 序列化

    #!/usr/bin/python # -*- coding: utf-8 -*- # 序列化: 例如把字典写进文件 info = { 'name': 'alex', 'age': 22 } f = ...

  5. BZOJ_2561_最小生成树_最小割

    BZOJ_2561_最小生成树_最小割 题意: 给定一个边带正权的连通无向图G=(V,E),其中N=|V|,M=|E|,N个点从1到N依次编号,给定三个正整数u,v,和L (u≠v),假设现在加入一条 ...

  6. centos7中输入ifconfig出现ens33,没有eth0

    vmware安装的centos7中没有出现eth0网卡,也没有ip,不能上网,输入ifconfig后如下图 解决办法 1.编辑网卡的配置文件 vi /etc/sysconfig/network-scr ...

  7. 面试题:求第K大元素(topK)?

    一.引言二.普通算法算法A:算法B:三.较好算法算法C:算法D:四.总结 一.引言 ​ 这就是类似求Top(K)问题,什么意思呢?怎么在无序数组中找到第几(K)大元素?我们这里不考虑海量数据,能装入内 ...

  8. java基础(六)-----String性质深入解析

    本文将讲解String的几个性质. 一.String的不可变性 对于初学者来说,很容易误认为String对象是可以改变的,特别是+链接时,对象似乎真的改变了.然而,String对象一经创建就不可以修改 ...

  9. Python爬虫入门教程 58-100 python爬虫高级技术之验证码篇4-极验证识别技术之一

    目录 验证码类型 官网最新效果 找个用极验证的网站 拼接验证码图片 编写自动化代码 核心run方法 模拟拖动方法 图片处理方法 初步运行结果 拼接图 图片存储到本地 @ 验证码类型 今天要搞定的验证码 ...

  10. python——绘制二元高斯分布的三维图像,

    在对数据进行可视化的过程中,可能经常需要对数据进行三维绘图,在python中进行三维绘图其实是比较简单的,下面我们将给出一个二元高斯分布的三维图像案例,并且给出相关函数的参数. 通常,我们绘制三维图像 ...