python并发编程之IO模型 同步 异步 阻塞 非阻塞
IO浅谈
首先
我们在谈及IO模型的时候,就必须要引入一个“操作系统”级别的调度者-系统内核(kernel),而阻塞非阻塞是跟进程/线程严密相关的,而进程/线程又是依赖于操作系统存在的,所以自然不能脱离操作系统来讨论阻塞非阻塞。同步/异步也是跟任务流相关的,所以要全面理解就必须考虑到并发的任务流,不然,肯定很难举出恰当的例子的。
本文讨论的背景是Linux环境下的network IO。
本文最重要的参考文献是Richard Stevens的“UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking ”,6.2节“I/O Models ”,Stevens在这节中详细说明了各种IO的特点和区别,如果英文够好的话,推荐直接阅读。Stevens的文风是有名的深入浅出,所以不用担心看不懂。本文中的流程图也是截取自参考文献。
在网络并发编程中,通俗的讲IO分为两个东西:1、等待 ==> 2、数据搬迁
或者这样说:当IO发生时,会涉及到对象和步骤,当进行网络IO(Network IO)时候,必须涉及到两个系统对象,一个不可避免的就是产生这个IO的进程或者线程(process or thread),还有另外一个老大级人物:系统内核(kernel),至于为何要让老大出场处理IO,究其原因就是,比如我们在进行读操作的时候,进程或线程是无法直接跟硬件打交道,无法直接从硬盘中直接拿到我们想要的数据,而是需要系统内核取帮我们去取,它取需要过程,有过程我们就得等待,系统内核取到了先会将数据放进它自己的内存空间中,我们要取还得从它的内存空间把数据迁移到进程的内存空间,这才算真正地拿到数据。
通俗的讲就是:
当一个read操作发生时,会经历两个阶段:
1)等待数据准备(Waiting for the data to be ready)
2)将数据从内核拷贝到进程(线程所在的)的内存中(Copying the data from the kernel to the process or thread)
四个概念
同步 synchronous
一个进程或线程在提交任务或发出调用后,要等待返回的最终结果后才算执行完毕,然后才会继续执行下一步操作
所谓同步,就是没得到最终结果之前,就不会继续下一步操作。
这就好比单行道过收费站一样,一个接着一个,只有上一个结束收费下一辆车才能开始进入站窗口交费。每辆车就相当与一个进程或线程。
其实绝大多数的函数都是同步调用,我们都是拿到结果之后在进行下一步代码操作。
而我们在谈及同步和异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。
异步 asynchronous
异步的概念与同步相对,当一个进程或线程发起一个异步功能调用或者说提交任务方式是异步提交的时,不会立即得到结果。它会继续执行下一步代码。而异步功能完成后,通过状态、通知或回调函数来通知调用者。
如果是通过状态在通知,那么调用者需要每隔一段时间检查一次结果是否返回,效率很低。
如果使用通知或者回调的方式,则进程或线程就不需要再做额外的操作,效率很高。
阻塞 blocking
首先阻塞是一种状态,一种进程或者线程的状态,不要把阻塞与同步混淆。
也就是说当进程或线程发起调用或提交任务之后,结果返回之前,比如遇到IO操作,则调用者(该进程或线程)就会被挂起,然后只有等到有结果后才会再将阻塞的线程激活。
非阻塞 non-blocking
非阻塞与阻塞相反,就算不能立即得到结果也不会将其挂起,而是会继续执行下一步。
四种常见IO模型
IO模型主要分五种
blocking IO 阻塞IO
nonblocking IO 非阻塞IO
IO multiplexing 复用型IO
signal driven IO 信号驱动型IO
asynchronous IO 异步IO
他们直接的区别点在于过程、进程(或线程)的状态、发起调用方式
首先最常见的IO模型:blocking IO
blocking IO
默认情况下,所有的socket都是阻塞IO,一个典型的read操作流程

non-blocking IO
设置socket可以使其变为非阻塞,当对一个非阻塞的socket执行读操作的时候,流程会不一样:

从图中可以看出,当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,
而是立刻返回一个error。从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。
用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦kernel中的数据准备好了,
并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。
所以,用户进程其实是需要不断的主动询问kernel数据好了没有。
IO multiplexing
IO multiplexing这个词可能有点陌生,但是如果我说select,epoll,大概就都能明白了。有些地方也称这种IO方式为event driven IO。我们都知道,select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。它的基本原理就是select/epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。它的流程如图:
当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
这个图和blocking IO的图其实并没有太大的不同,事实上,还更差一些。因为这里需要使用两个system call (select 和 recvfrom),而blocking IO只调用了一个system call (recvfrom)。但是,用select的优势在于它可以同时处理多个connection。(多说一句。所以,如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。)
在IO multiplexing Model中,实际中,对于每一个socket,一般都设置成为non-blocking,但是,如上图所示,整个用户的process其实是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。
Asynchronous I/O

用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。
小结
blocking和non-blocking的区别
调用blocking IO会一直block住对应的进程直到操作完成,而non-blocking IO在内核准备数据这个阶段,进程是不会非阻塞状态。
synchronous IO和asynchronous IO的区别
同步IO在进行IO操作的时候会将进程阻塞,而异步IO却不会。
所以blocking IO,non-blocking IO,IO multiplexing都属于synchronous IO,而asynchronous IO则不一样,当进程发起IO 操作之后,就直接返回再也不理睬了,直到kernel发送一个信号,告诉进程说IO完成。在这整个过程中,进程完全没有被block。
最后各个IO Model的比较如图所示:

————————————————
版权声明:本文为CSDN博主「historyasamirror」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/historyasamirror/article/details/5778378
python并发编程之IO模型 同步 异步 阻塞 非阻塞的更多相关文章
- Python并发编程之IO模型
目录 IO模型介绍 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) IO多路复用 异步IO IO模型比较分析 selectors模块 一.IO模型介绍 Stevens ...
- python并发编程之IO模型,
了解新知识之前需要知道的一些知识 同步(synchronous):一个进程在执行某个任务时,另外一个进程必须等待其执行完毕,才能继续执行 #所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调 ...
- python并发编程之IO模型(Day38)
一.IO模型介绍 为了更好的学习IO模型,可以先看同步,异步,阻塞,非阻塞 http://www.cnblogs.com/linhaifeng/articles/7430066.html#_label ...
- 33 python 并发编程之IO模型
一 IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非 ...
- 五 python并发编程之IO模型
一 IO模型介绍 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问 ...
- python并发编程之IO模型(实践篇)
一.阻塞IO 介绍略(请看概念篇) 二.非阻塞IO 在非阻塞式IO中,用户进程需要不断的主动询问kernel数据准备好了没有 # 服务端 import socket import time serve ...
- 第十篇.6、python并发编程之IO模型
一 IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非 ...
- 第 13 章 python并发编程之io模型
一.IO模型介绍 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问 ...
- 38、python并发编程之IO模型
目录: 一 IO模型介绍 二 阻塞IO(blocking IO) 三 非阻塞IO(non-blocking IO) 四 多路复用IO(IO multiplexing) 五 异步IO(Asynchron ...
随机推荐
- 原生js如何判断元素出现在可视区
元素出现在可视区 scorll滑动的距离>=当前元素距离浏览器最顶端的高度+当前元素自身的高度-当前可视区的高度 触底 scorll滑动的距离>=当前scroll总高度-当前可视区的高度
- 2019.10.1 qbxt模拟题
第一题 考虑树上\(DP\),f[i][j][0/1]表示以\(i\)为根的子树,入读为零点的个数为\(j\),点\(i\)的入度为\(0\)/不为\(0\)时的方案数 转移的时候考虑\(u\)的一个 ...
- UltraISO 下载
链接:https://pan.baidu.com/s/1Wf0TmB8L9falKyGu8NwvBw 提取码:1cu8 参考: https://jingyan.baidu.com/article/cb ...
- Tecplot显示周期和对称算例
源视频链接:https://pan.baidu.com/s/1HdU3nsti8qLZhXvISxsSFA 提取码: 3kfu 模型链接:https://pan.baidu.com/s/1CQCGL7 ...
- oracle--CKPT
一,CKPT功能 ) 调度数据写: ) 会将已经完成的检查点写到数据文件头: ) 把已经完成的检查点写到控制文件: . other:其他进程: . 注意:磁盘.内存支持并行I/O,磁带不支持: . 服 ...
- oracle使用Union时遇到列格式clob和varchar2不符,不能转的问题
其实这个很简单,思路就是把clob转为varchar,在查询的时候使用dbms_lob.substr(coulmn,4000):就可以把指定列从clob转化为varchar2.
- Linux(环境篇):系统搭建本地FTP后,无法登录(331 Please specify the password.)问题解决
首先 Linux 搭建ftp,开放21端口.(省略...) 你可能会遇到以下问题:错误 SELinux is disabled 解决: setenforce: SELinux is disabled ...
- android细节之android.intent.category.DEFAULT的使用
我们知道,实现android的Activity之间相互跳转需要用到Intent, Intent又分为显式Intent和隐式Intent, 显式Intent很简单,比如我在FirstActivity中想 ...
- 009 webpack将ES高级语法进行装换
一:ES高级转换 1.main.js中的js不能解析 // js的主要入口 import $ from 'jquery' import './css/index.css' import './css/ ...
- java 欢迎页 主页 设置为servlet的方法
[参考]Java Web 设置默认首页 [参考]设置servlet或action作为欢迎页面 1. 使用HTML<meta>标签跳转至servlet <META HTTP-EQUI ...