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 ...
随机推荐
- Numpy | 12 数组操作
Numpy 中包含了一些函数用于处理数组,大概可分为以下几类: 修改数组形状 翻转数组 修改数组维度 连接数组 分割数组 数组元素的添加与删除 一.修改数组形状 函数 描述 reshape 不改变数据 ...
- 苹果MAC OS查看MAC地址及修改ip
一,查看mac地址 第一步: 第二步: 第三步: 二,更改IP 第一步: 第二步: 第三步: 最后点击“好”就完成了 我要这天再遮不住我眼,要这地再埋不了我心.要这天下众生都明白我意,要那诸佛都烟消云 ...
- Reactive Extensions (Rx) 入门(2) —— 安装 Reactive Extensions
译文:https://blog.csdn.net/fangxing80/article/details/7581937 原文:http://www.atmarkit.co.jp/fdotnet/int ...
- SDOI 二轮垫底鸡
SDOI 二轮垫底鸡 day0 准备爆零 没啥好准备考试的,12.00出发,试机敲抄个ntt,在宾馆不知道颓啥. day1 爆零爬山 T1noip的题目也放到省选上. 第一档线段树?肯定不写,直接上1 ...
- pycharm配置默认代码和注释模板
有人问,在pycharm新建python文件时,文件开头的注释每次都要重复写,能不能配置成模板?其实pycharm本身自带此功能 在pycharm菜单栏找File -> settings -&g ...
- 理解Docker :Docker 网络
本系列文章将介绍 Docker的相关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...
- php 加载 zip 文件
header('Content-type: application/zip');header('Content-Disposition: attachment; filename="Quer ...
- Linux的tmpfs和ramfs
tmpfs tmpfs是一种虚拟内存文件系统, 它的存储空间在VM里面,现在大多数操作系统都采用了虚拟内存管理机制, VM(Virtual Memory) 是由Linux内核里面的VM子系统管理. V ...
- arcpy实例教程-地图图层导出到要素类
arcpy实例教程-地图图层导出到要素类 商务合作,科技咨询,版权转让:向日葵,135-4855_4328,xiexiaokui#qq.com 功能:将选定图层的范围导出到内存要素类 描述:将选定图层 ...
- eclispe: 修改所有文件默认编码为UTF-8
1.修改 workspace text file encoding 依次点击windows -> Preferences -> general -> Workspace,修改如图的编 ...