python的io多路复用_python之路10:IO多路复用

IO模型

select模块

selectors模块

IO模型

网络IO的本质是socket的读取,socket在linux系统中被抽象为流,IO可以理解为对流的操作.对于一次IO访问,数据会先被拷到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间,所以说当一个read操作发生时,它会经理两个阶段:

第一阶段:等待数据准备;第二阶段:将数据从内核拷贝到进程中

对socket流而言:第一步:通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区。第二步:把数据从内核缓冲区复制到应用进程缓冲区。

IO的模型大致有如下几种:

异步IO(asynchronous IO)

同步IO(synchronous IO)

阻塞IO(bloking IO)

非阻塞IO(non-blocking IO)

多路复用IO(multiplexing IO)

信号驱动式IO(signal-driven IO)

同步阻塞 IO(blocking IO)

同步非阻塞 IO(nonblocking IO)

IO 多路复用( IO multiplexing)

信号驱动式 IO(signal-driven IO)

异步非阻塞 IO(asynchronous IO)

五种模型总结

select模块

Python中有一个select模块,其中提供了:select、poll、epoll三个方法,分别调用系统的 select,poll,epoll 从而实现IO多路复用,有些地方也称这种IO方式为event driven IO。select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。它的基本原理就是select,poll,epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。

select(rlist, wlist, xlist, timeout=None)

select 函数监视的文件描述符分3类,分别是readfds、writefds和exceptfds。调用后select函数会阻塞,直到有描述副就绪(有数据 可读、可写、或者有except),或者超时(timeout指定等待时间,如果立即返回设为null即可),函数返回。当select函数返回后,可以 通过遍历fdset,来找到就绪的描述符。

应用:

1 #!/usr/bin/env python

2 #-*- coding:utf-8 -*-

3 __author__ = 'BillyLV'

4

5 from socket import *

6 importselect7

8 server = socket(AF_INET, SOCK_STREAM) #ipv4, tcp

9 server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) #端口重用

10 server.bind(('127.0.0.1', 8090))11 server.listen(10)12 server.setblocking(False) #设置socket的套接字为非阻塞

13 read_l = [server, ] #因为不只就那么一个列表要检测,所以不要在参数里面定死了

14 whileTrue:15 r_l, w_l, x_l =select.select(read_l, [], [])16 print(r_l) #检测到有数据

17 for ready_obj inr_l:18 if ready_obj ==server:19 conn, addr = ready_obj.accept() #accept要经历两个阶段,但是程序如果走到这一步,那肯定是数据准备好了

20 #print(addr)

21 read_l.append(conn)22 else:23 try:24 data = ready_obj.recv(1024) #此时的ready_obj等于conn

25 if notdata:26 read_l.remove(ready_obj)27 continue

28 ready_obj.send(data.upper())29 exceptConnectionResetError:30 read_l.remove(ready_obj)

服务端IO多路复用

1 #!/usr/bin/env python

2 #-*- coding:utf-8 -*-

3 __author__ = 'BillyLV'

4

5 from socket import *

6 client = socket(AF_INET, SOCK_STREAM) #ipv4, tcp

7 client.connect(('127.0.0.1', 8091))8 whileTrue:9 msg = input('>>:')10 if notmsg:11 continue

12 client.send(msg.encode('utf-8'))13 data = client.recv(1024)14 print(data.decode('utf-8'))

客户端IO多路复用

selectors模块

Select\Poll\Epoll这三种IO多路复用模型在不同的平台有着不同的支持,相对于select和poll来说,epoll更加灵活,没有描述符限制。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。而epoll在windows下就不支持,好在我们有selectors模块,帮我们默认选择当前平台下最合适的。该模块允许基于所选模块原语的高水平和高效的IO多路复用。鼓励用户使用此模块,除非他们希望对所使用的操作系统级原语进行精确控制。

1 #!/usr/bin/env python

2 #-*- coding:utf-8 -*-

3 __author__ = 'BillyLV'

4

5 importselectors6 from socket import *

7

8 sel = selectors.DefaultSelector() #选择最佳实施

9

10

11 defaccept(server_fileobj, mask):12 conn, addr =server_fileobj.accept()13 print('accepted', conn, 'from', addr)14 conn.setblocking(False)15 sel.register(conn, selectors.EVENT_READ, read)16

17

18 defread(conn, mask):19 data = conn.recv(1024)20 ifdata:21 print('echoing', repr(data), 'to', conn)22 conn.send(data)23 else:24 print('closing', conn)25 sel.unregister(conn)26 conn.close()27

28

29 server_fileobj =socket(AF_INET, SOCK_STREAM)30 server_fileobj.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)31 server_fileobj.bind(('localhost', 2130))32 server_fileobj.listen(200)33 server_fileobj.setblocking(False) #设置socket的接口为非阻塞

34 #相当于往select的读列表里append了一个文件句柄server_fileobj,并且绑定了一个回调函数accept

35 sel.register(server_fileobj, selectors.EVENT_READ, accept)36

37 whileTrue:38 events = sel.select() #检测所有的fileobj,是否有完成wait data的

39 for sel_obj, mask inevents:40 callback = sel_obj.data #callback=accpet

41 callback(sel_obj.fileobj, mask) #accpet(server_fileobj,1)

服务端

1 #!/usr/bin/env python

2 #-*- coding:utf-8 -*-

3 __author__ = 'BillyLV'

4

5 from socket import *

6 client = socket(AF_INET, SOCK_STREAM) #ipv4, tcp

7 client.connect(('localhost', 2130))8 whileTrue:9 msg = input('>>:')10 if notmsg:11 continue

12 client.send(msg.encode('utf-8'))13 data = client.recv(1024)14 print(data.decode('utf-8'))

客户端

参考:

http://www.cnblogs.com/alex3714

http://www.cnblogs.com/wupeiqi

internet&python books

PS:如侵权,联我删。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值