Python开发基础-Day33 IO模型
IO模型分类
五种IO Model
blocking IO 阻塞IO
nonblocking IO 非阻塞IO
IO multiplexing IO多路复用
signal driven IO 信号驱动IO
asynchronous IO 异步IO
signal driven IO(信号驱动IO)在实际中并不常用,所以只剩下四种IO Model。
网络IO的两个过程
对于一个network IO ,会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(kernel)。当一个read操作发生时,它会经历两个阶段:
- 等待数据准备 (Waiting for the data to be ready):等待系统接收数据
- 将数据从内核拷贝到进程中 (Copying the data from the kernel to the process):进程从系统缓存中拿到数据
同步IO:在这两个过程中有任意阶段出现阻塞状态。
阻塞IO、非阻塞IO、IO多路复用都是同步IO
异步IO:全程无阻塞的IO
异步IO属于异步IO(真的没毛病)
阻塞IO(Blocking IO)

UDP包:当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据。对于network io来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候kernel就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来。
blocking IO的特点就是在IO执行的两个阶段都被block了。
示例:
#服务端
import socket
sock=socket.socket() #默认是TCP
sock.bind(("127.0.0.1",8088)) sock.listen(5)
while True:
conn,addr=sock.accept() #默认是就是阻塞的方式,监听等待客户端连接(阶段一):等待中的阻塞
#客户端连接后接收数据(阶段二):socket对象和客户端地址,虽然接收数据的过程很快但是实际上也是阻塞
while True:
data=conn.recv(1024) #也是两个阶段的阻塞
print(data.decode('utf8'))
if data.decode('utf8') =='q':
break
respnse=input('>>>>')
conn.send(respnse.encode('utf8')) #客户端
import socket
sock=socket.socket()
sock.connect(("127.0.0.1",8088)) while True:
data=input('>>>').strip()
sock.send(data.encode('utf8'))
s_data = sock.recv(1024) #两个阶段的阻塞
print(s_data.decode('utf8'))
非阻塞IO(Non-blocking IO)

当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。所以用户进程不需要等待,而是马上就得到了一个结果,用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。这个过程中,用户进程是需要不断的主动询问kernel数据好了没有。
非阻塞实际上是将大的整片时间的阻塞分成N多的小的阻塞,每次recvform系统调用之间,可以干点别的事情,然后再发起recvform系统调用,重复的过程通常被称之为轮询。轮询检查内核数据,直到数据准备好,再拷贝数据到进程,进行数据处理。需要注意,拷贝数据整个过程,进程仍然是属于阻塞的状态。
优点:能够在等待任务完成的时间里干其他活了(包括提交其他任务,也就是 “后台” 可以有多个任务在同时执行)。
缺点:任务完成的响应延迟增大了,因为每过一段时间才去轮询一次read操作,而任务可能在两次轮询之间的任意时间完成。这会导致整体数据吞吐量的降低。
#服务端 import socket
import time
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #默认是TCP
sock.bind(("127.0.0.1",8088))
sock.listen(5)
sock.setblocking(False) while True:
try:
print('server waiting')
conn, addr = sock.accept() # 默认是个阻塞的方式,等待客户端连接
while True:
data = conn.recv(1024) #这边也是阻塞的IO
print(data.decode('utf8'))
if data.decode('utf8') == 'q':
break
respnse = input('>>>>')
conn.send(respnse.encode('utf8'))
except Exception as e:
print (e)
time.sleep(4) #客户端
import socket
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #默认是TCP while True:
sock.connect(("127.0.0.1", 8088)) #因为服务端recv也是非阻塞,所以要不断重新连接
data=input('>>>').strip()
sock.send(data.encode('utf8'))
s_data = sock.recv(1024)
print(s_data.decode('utf8'))
IO多路复用(IO multiplexing)
IO多路复用,也叫做event driven IO,实现方式:select,poll或epoll
IO多路复用的好处就在于单个process就可以同时处理多个网络连接的IO

用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。这个过程中有两次system call(系统调用) select阻塞时候 和 recvfrom阻塞时候。用多路复用的的优势在于它可以同时处理大批量的connection,不适用单个或少量,少量还不如multi-threading + blocking IO。
select示例:
#服务端
import socket
import select
sock=socket.socket()
sock.bind(("127.0.0.1",8088))
sock.listen(5) inp=[sock,] #定义监听的套接字对象列表,列表列表里可以有多个对象 while True:
#字段顺序:input list 、output list、error list、date(可以不写)
r=select.select(inp,[],[],None) #对比的是sock.accept(),这一步只做了监听的事情,监听哪个socket对象活动,当没有客户端连接时候会阻塞
# 当监听到有活动的socket对象时候,将返回值给r
print('r',r)
print('r',r[0])
#r接收的返回是一个元组,r[0]是活动的对象列表 for obj in r[0]:
if obj == sock: #如果活动的对象是sock,那么将客户端对象加入监听列表,客户端再发数据时候,触发客户端的对象活动
conn,addr=obj.accept() #accept只做第二个阶段的事情,取回数据:client的socket对象和地址
print(conn,addr)
inp.append(conn)
else:
data=obj.recv(1024)
print(data.decode('utf8'))
resp=input('>>>')
obj.send(resp.encode('utf8')) #客户端
import socket
sock=socket.socket()
sock.connect(("127.0.0.1", 8088))
while True:
data=input('>>>').strip()
sock.send(data.encode('utf8'))
s_data = sock.recv(1024)
print(s_data.decode('utf8'))
因为使用的是for循环,当多个客户端发消息给服务端,只能一个个顺序处理。
在windows下只能用select实现多路复用
在Linux可以使用select、poll、epoll实现,推荐使用epoll,对比:
select和poll的监听方式为轮询方式,即每次都要循环一遍监听列表,效率低,另外select有连接数限制,poll无限
epoll连接数无限,区别在于监听方式不同,每个socket对象绑定一个回调函数,当socket对象活动了就触发回调函数,把自己写到活动列表中,epoll直接调用活动列表
信号驱动IO(signal driven IO)
不常用,不做说明
异步IO(Asynchronous I/O)

用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。
IO模型区别

selectors模块
该模块能够按照系统平台,自动选择多路复用的方式。
#服务端
import selectors
import socket sel=selectors.DefaultSelector() def accept(sock,mask):
conn,addr=sock.accept() #4、获取客户端的conn对象和地址
print('accetped',conn,'from',addr)
conn.setblocking(False)
sel.register(conn,selectors.EVENT_READ,read) #5、注册conn对象,将conn对象和函数read绑定 def read(conn,mask):
data=conn.recv(1024) #9、服务端通过conn对象接收消息,进行下面的逻辑处理
if data:
print('echoing',repr(data),'to',conn)
conn.send(data)
else:
print('closing',conn)
sel.unregister(conn)
conn.close() sock=socket.socket()
sock.bind(('127.0.0.1',8088))
sock.listen(100)
sock.setblocking(False)
sel.register(sock,selectors.EVENT_READ,accept) #sock对象注册绑定accept函数 while True:
#不管是哪个方式,都是使用select方法监听活动的socket对象
events=sel.select() #1、执行sel阻塞监听,当有客户端连接,激活sock对象,返回一个存放活动sock对象相关信息的列表
#6、客户端通过conn对象发送消息,激活sel监听列表中的的conn对象,返回一个存放活动conn对象相关信息的列表
print(events,type(events))
for key,mask in events:
print(mask)
print(key.data) #socket对象注册绑定的accept函数
print(key.fileobj)
callback=key.data #2、取得返回的sock绑定的函数
#7、取得返回conn绑定的函数
callback(key.fileobj,mask) #3、key.fileobj是sock对象,执行函数
#8、执行函数read,并传入conn对象 #客户端
import socket
sock=socket.socket()
sock.connect(("127.0.0.1", 8088))
while True:
data=input('>>>').strip()
sock.send(data.encode('utf8'))
s_data = sock.recv(1024)
print(s_data.decode('utf8'))
Python开发基础-Day33 IO模型的更多相关文章
- Python文件基础操作(IO入门1)
转载请标明出处: http://www.cnblogs.com/why168888/p/6422270.html 本文出自:[Edwin博客园] Python文件基础操作(IO入门1) 1. pyth ...
- python 全栈开发,Day44(IO模型介绍,阻塞IO,非阻塞IO,多路复用IO,异步IO,IO模型比较分析,selectors模块,垃圾回收机制)
昨日内容回顾 协程实际上是一个线程,执行了多个任务,遇到IO就切换 切换,可以使用yield,greenlet 遇到IO gevent: 检测到IO,能够使用greenlet实现自动切换,规避了IO阻 ...
- python基础27 -----python进程终结篇-----IO模型
一.IO模型 1.IO模型分类 1.阻塞IO--------blocking IO 2.非阻塞IO------nonblocking IO 3. 多路复用IO------- multiplexing ...
- python基础(17)-IO模型&selector模块
先说一下IO发生时涉及的对象和步骤.对于一个network IO (这里我们以read举例),它会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(k ...
- python基础之IO模型
IO模型分类 五种IO Model blocking IO 阻塞IO nonblocking IO 非阻塞IO IO multiplexing IO多路复用 signal driven IO 信号驱动 ...
- python网络编程——网络IO模型
1 网络IO模型介绍 服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型. (2)同步非阻塞IO(Non-bl ...
- Python socket编程之IO模型介绍(多路复用*)
1.I/O基础知识 1.1 什么是文件描述符? 在网络中,一个socket对象就是1个文件描述符,在文件中,1个文件句柄(即file对象)就是1个文件描述符.其实可以理解为就是一个“指针”或“句柄”, ...
- 还在用Alpine作为你Docker的Python开发基础镜像?其实Ubuntu更好一点
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_173 一般情况下,当你想为你的Python开发环境选择一个基础镜像时,大多数人都会选择Alpine,为什么?因为它太小了,仅仅只有 ...
- Python并发编程之IO模型
目录 IO模型介绍 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) IO多路复用 异步IO IO模型比较分析 selectors模块 一.IO模型介绍 Stevens ...
随机推荐
- uva 1639 Candy (对数处理精度)
https://vjudge.net/problem/UVA-1639 有两个盒子各有n(n≤2*10 5 )个糖,每天随机选一个(概率分别为p,1-p),然后吃一颗糖. 直到有一天,打开盒子一看,没 ...
- 2015/11/2用Python写游戏,pygame入门(2):游戏中的事件和显示
pygame是一个比较大的库,以我这点弱小的实力是没办法详解的.所以我只讲我懂得那些部分,其他部分由大家慢慢查找了解. ------------------------------- 我用pygame ...
- 「七天自制PHP框架」第一天:路由与控制器
我们为什么要使用路由? 原因1:一个更漂亮的URI 1.URI的改进 刚刚开始学PHP时,我们一定写过blog.php?id=1之类的URI,使用GET方式获取参数.这样的URI有两个缺点,一是容易被 ...
- js-打地鼠游戏开发
[生成画布] 第1课[随机生成地鼠] 第2课[定时生成地鼠] 第3课[打地鼠完结篇] 第4课 优酷在线播放地址 http://list.youku.com/albumlist/show?id=2939 ...
- JavaScript 判断手机端访问并跳转 redirect mobile
假如你的手机端网站在 /m 目录下 (function(a,b){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer| ...
- MySQL5.6.26升级到MySQL5.7.9实战方案【转】
MySQL5.6.26升级到MySQL5.7.9实战方案 转自 MySQL5.6.26升级到MySQL5.7.9实战方案 - 其他网络技术 - 红黑联盟http://www.2cto.com/net/ ...
- Spring是什么+控制反转和依赖注入
Spring是一个开源框架,是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架. 原因: (1)通过控制反转(IOC)达到松耦合,IOC也就是把控制权交出去,在使用中直接得到对象 (2)提 ...
- Lempel-Ziv algorithm realization
Lempel-Ziv 复杂度程序 随着人们对非线性方法的分析越加深入,他们发现,虽然关联维度和最大李雅谱诺夫指数在分析脑电时具有一定的帮助,但是它们对数据的依赖性太强,对干扰和噪 声太敏感,而且要得到 ...
- C/C++——[05] 函数
函数是 C/C++语言中的一种程序组件单位.一个函数通常代表了一种数据处理的功能,由函数体和函数原型两部分组成.函数原型为这个数据处理功能指定一个标识符号(函数的名称).说明被处理数据的组成及其类型. ...
- GitHub vs GitLab:它们有什么区别?
查看原文GitLab vs. GitHub: How Are They Different? 两者都是基于web的Git repositories(仓库),拥有流水线型的web开发流程,它们为开发团队 ...