Python I/O多路复用 阻塞、非阻塞、同步、异步
一、python 之 IO多路复用
-
1.1 多路复用概念:
监听多个描述符(文件描述符(windows下暂不支持)、网络描述符)的状态,如果描述符状态改变 则会被内核修改标志位,进而被进程获取进而进行读写操作
-
1.2 多路复用两种触发方式:
水平触发(Level Triggered):
将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll()的时候将再次报告这些文件描述符,所以它们一般不会丢失就绪的消息,但是会增加消耗
边缘触发(Edge Triggered):
只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,理论上边缘触发的性能要更高一些,但是代码实现相当复杂。
-
1.3 阻塞/非阻塞 模式:
阻塞:
如果阻塞模式则等待数据
非阻塞:
如果非阻塞模式有数据返回数据、无数据直接返回报错
-
1.4 I/O模型:
同步I/O:
一问一答 等待数据(阻塞模式)或 不管有没有数据都返回(非阻塞模式)
异步I/O:
用户进程问完之后干别的处理结果出来之后告知用户进程
-
1.5 selec/poll/epoll
相同点和不同点图解
select/poll/epoll详解
Python IO复用之select
格式:
rList,wList,eList = select.select(argv1,argv2,argv3,timeout)
参数:
argv1 标准输入
argv2 如果监听序列中句柄发生变化 则将变化句柄返回至wList
argv3 如果监听序列中句柄有错误时 则将错误句柄返回到eList
timeout 设置阻塞时间,如果为2那么将阻塞2s,如果不设置则默认一直阻塞
实例:
select 服务端:
#!/usr/bin/env python #-*- coding:utf-8 -*- import select,socket sock1 = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server_address = ('127.0.0.1',8081) sock1.bind(server_address) sock1.listen(5) #制定select监听列表sock1为select监听的一个元素 input_list = [sock1,] while True: #当input_list中的句柄发生变化时,select会将发生变化的句柄添加到rList列表中 rList,wList,eList = select.select(input_list,[],[]) #打印出当前rList中的元素 你会发现没有客户端连接的时候rList是空的 当有连接过来时rList就会发生改变 print rList #循环发生变化的句柄列表 for r in rList: #如果句柄是sock1 进入监听状态 并将客户端socket对象(conn)添加到input_list if r == sock1: conn,address = r.accept() print address input_list.append(conn) #如果不是sock1 那么就是上面添加的客户端socket对象(conn) else: data = r.recv(1024) r.send(data)
socket 客户端
#!/usr/bin/env python #-*- coding:utf-8 -*- import socket socket_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server_address = ('127.0.0.1',8081) socket_client.connect(server_address) while True: string = raw_input('please input:') socket_client.send(string) server_data = socket_client.recv(1024) print server_data socket_client.close()
(注:执行多个客户端你会发现一个很有趣的现象)
Ø 1.2 Python IO复用之poll
触发方式:
水平触发
只适用于Unix/Linux操作系统
Ø 1.3 Python IO复用之epoll
触发方式:
边缘触发
只适用于Unix/Linux操作系统
作者:Alan
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利!