python3.x Day6 IO多路复用
IO多路复用
import asyncio 这个是异步IO模块 这个还不知道怎么用 select poll epoll 都是IO多路复用 windows 仅支持select linux2.6以后 支持epoll epoll是相当厉害的 详细的描述参考:http://www.cnblogs.com/alex3714/articles/5876749.html select、poll、epoll区别:http://www.cnblogs.com/alex3714/p/4372426.html 先来写一个用select方式的socket模型
import select #引入select模块,这是利用操作系统的select处理方式,windows、linux、unix都支持
import socket
import sys
import queue server = socket.socket()
server.setblocking(0) server_addr = ('0.0.0.0',9999) print('starting up on %s port %s' % server_addr)
server.bind(server_addr) server.listen(5) inputs = [server, ] #自己也要监测呀,因为server本身也是个fd
outputs = [] message_queues = {} while True:
print("waiting for next event...") readable, writeable, exeptional = select.select(inputs,outputs,inputs) #如果没有任何fd就绪,那程序就会一直阻塞在这里 for s in readable: #每个s就是一个socket if s is server: #别忘记,上面我们server自己也当做一个fd放在了inputs列表里,传给了select,如果这个s是server,代表server这个fd就绪了,
#就是有活动了, 什么情况下它才有活动? 当然 是有新连接进来的时候 呀
#新连接进来了,接受这个连接
conn, client_addr = s.accept()
print("new connection from",client_addr)
conn.setblocking(0)
inputs.append(conn) #为了不阻塞整个程序,我们不会立刻在这里开始接收客户端发来的数据, 把它放到inputs里, 下一次loop时,这个新连接
#就会被交给select去监听,如果这个连接的客户端发来了数据 ,那这个连接的fd在server端就会变成就续的,select就会把这个连接返回,返回到
#readable 列表里,然后你就可以loop readable列表,取出这个连接,开始接收数据了, 下面就是这么干 的 message_queues[conn] = queue.Queue() #接收到客户端的数据后,不立刻返回 ,暂存在队列里,以后发送 else: #s不是server的话,那就只能是一个 与客户端建立的连接的fd了
#客户端的数据过来了,在这接收
try:
data = s.recv(1024)
except ConnectionResetError as e:
data=None
print(e)
print("客户端断开了", s)
if s in outputs:
outputs.remove(s) # 清理已断开的连接
inputs.remove(s) # 清理已断开的连接
del message_queues[s] ##清理已断开的连接
if data:
print("收到来自[%s]的数据:" % s.getpeername()[0], data)
message_queues[s].put(data) #收到的数据先放到queue里,一会返回给客户端
if s not in outputs:
outputs.append(s) #为了不影响处理与其它客户端的连接 , 这里不立刻返回数据给客户端 else:#如果收不到data代表什么呢? 代表客户端断开了呀
print("客户端断开了",s) if s in outputs:
outputs.remove(s) #清理已断开的连接
if s in inputs:
inputs.remove(s) #清理已断开的连接
if s in message_queues.keys():
del message_queues[s] ##清理已断开的连接 for s in writeable:
try :
next_msg = message_queues[s].get_nowait() except queue.Empty:
print("client [%s]" %s.getpeername()[0], "queue is empty..")
outputs.remove(s) else:
print("sending msg to [%s]"%s.getpeername()[0], next_msg)
s.send(next_msg.upper()) for s in exeptional:
print("handling exception for ",s.getpeername())
inputs.remove(s)
if s in outputs:
outputs.remove(s)
s.close() del message_queues[s]
再来一个升级版本的,selectors模块,它底层是看操作系统的,默认是epoll,但是如果不支持,比如windows,linux kernel < 2.6,就用select模式
import selectors,socket #selectors 超牛的IO多路复用的模块,支持select poll epoll ,优先epoll sel=selectors.DefaultSelector() def accpect(sock,mask): #创建业务连接的方法
conn,addr=sock.accept()
print("accept:",conn,"from:",addr)
conn.setblocking(False)
sel.register(fileobj=conn,events=selectors.EVENT_READ,data=read) def read(conn,mask): #连接以后 执行业务的方法
data=conn.recv(1024)
if data:
print("recv data:",data,"conn:",conn)
# print(conn.getsockname())
conn.send(data)
else:
print("close:",conn)
sel.unregister(fileobj=conn)
conn.close() server=socket.socket()
server.bind(("0.0.0.0",9999))
server.listen(10000)
server.setblocking(False) sel.register(fileobj=server,events=selectors.EVENT_READ,data=accpect) #只需要注册需要并发使用IO的应用,明确对应的回调data内容就行了 while True:
events=sel.select()
print("已经注册sel数量:")
for key,mask in events:
callback=key.data #获取注册时的sel.register()方法参数中的data对应的内容,之前放进去的有accpect和read函数
callback(key.fileobj,mask)
这里注意,有个非常非常尴尬的问题情景:
需求:
1、基于socket
2、要多进程处理业务(多线程由于GIL锁,多核也无法真正同时刻处理,所以用多进程)
3、进程内必须是selectors处理连接
此时,就非常尴尬了,原因是多进程multiprocessing模块,IO多路复用selectors模块,他俩有矛盾:
矛盾就是:
multiprocessing就是认为socket是阻塞的,
selectors要求socket必须是非阻塞的,不然没办法监听活动。
那么socket怎么办呢,这个问题,在windows还好,因为select方式还是慢,显不出来,linux epoll超快的,直接就严重影响业务了
我是这么解决这个矛盾的
需要多次接收或发送 或者 循环发送循环接收的业务情景,selectors监听到后,步骤:
1、从selectors实例中注销掉这个业务连接,
2、设定这个业务连接为阻塞,
3、开始进行上述情景业务,
4、再设定为非阻塞,
5、重新注册回selectors
python3.x Day6 IO多路复用的更多相关文章
- socket_server源码剖析、python作用域、IO多路复用
本节内容: 课前准备知识: 函数嵌套函数的使用方法: 我们在使用函数嵌套函数的时候,是学习装饰器的时候,出现过,由一个函数返回值是一个函数体情况. 我们在使用函数嵌套函数的时候,最好也这么写. def ...
- python运维开发(十)----IO多路复用线程基本使用
内容目录: python作用域 python2.7和python3.5的多继承区别 IO多路复用 socketserver模块源分析 多线程.进程.协程 python作用域 python中无块级作用 ...
- Python实战之IO多路复用select的详细简单练习
IO多路复用 I/O多路复用指:通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作. select 它通过一个select()系统调用来 ...
- IO模式和IO多路复用
网络编程里常听到阻塞IO.非阻塞IO.同步IO.异步IO等概念,总听别人装13不如自己下来钻研一下.不过,搞清楚这些概念之前,还得先回顾一些基础的概念. 1 基础知识回顾 注意:咱们下面说的都是Lin ...
- 转载 io多路复用
作者:ZingpLiu 出处:http://www.cnblogs.com/zingp/ 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接. 回到 ...
- IO模式和IO多路复用详解
网络编程里常听到阻塞IO.非阻塞IO.同步IO.异步IO等概念,总听别人装13不如自己下来钻研一下.不过,搞清楚这些概念之前,还得先回顾一些基础的概念. 1 基础知识回顾 注意:咱们下面说的都是Lin ...
- epoll——IO多路复用选择器
上上篇博客讲的套接字,由于其阻塞性而导致一个服务端同一时间只能与一个客户端连接.基于这个缺点,在上篇博客我们将其设置为非阻塞实现了一个服务端同一时间可以与多个客户端相连,即实现了并发,但其同样留下了一 ...
- 网络编程socket 结合IO多路复用select; epool机制分别实现单线程并发TCP服务器
select版-TCP服务器 1. select 原理 在多路复用的模型中,比较常用的有select模型和epoll模型.这两个都是系统接口,由操作系统提供.当然,Python的select模块进行了 ...
- Python(七)Socket编程、IO多路复用、SocketServer
本章内容: Socket IO多路复用(select) SocketServer 模块(ThreadingTCPServer源码剖析) Socket socket通常也称作"套接字" ...
随机推荐
- Mac 开发 Hue
1)环境准备 Maven 3.6.1 python (Anaconda 2.7.16) MySQL 5.7 git 2.21 2)Hue源码下载 git clone git@github.com:ar ...
- Python中lambda表达式的应用
lambda表达式 Python中定义了一个匿名函数叫做lambda表达式,个人理解实现的作用就是代替一些简单的函数,使得代码看上去更简洁并且可读性高.举个例子,我们有一个元组列表[(‘a’,1),( ...
- iOS Swift3 用全局“宏”时要注意的问题
当你需要定义一个APP全局“宏”来调用 UserDefaults.standard里存储的值的时候, 一定要将这个“宏”定义为计算属性,否则你得到的值只会在APP启动的时候计算一次. 示例如下: va ...
- CF850 E. Random Elections
题目传送门:CF 题目大意: 现有\(A,B,C\)三人参加竞选,有n个市民对其进行投票,每个市民心中对三人都有一个优先顺序(如市民\(i\)对三人的优先顺序为\(A-C-B\),则凡是有\(A\)的 ...
- queue+模拟 Codeforces Round #304 (Div. 2) C. Soldier and Cards
题目传送门 /* 题意:两堆牌,每次拿出上面的牌做比较,大的一方收走两张牌,直到一方没有牌 queue容器:模拟上述过程,当次数达到最大值时判断为-1 */ #include <cstdio&g ...
- 1-3方法的重载(overload)
之前已经写了一个方法sumInt用来计算两个int类型数字的和,如果要是想计算两个float类型数字的和呢?ok,那就再来写一个sumFloat方法,除此之外,还有long类型,double类型,如果 ...
- Eclipse的ant调用maven
需要在 eclipse 的 windows - preferences - ant - runtime - classpath - global entries 加入 eclipse 里面的 jsch ...
- python_10(模块与包)
第1章 模块 1.1 模块的种类 1.2 定义 1.3 作用 1.4 导入及使用 1.4.1 import 1.4.2 测试一: 1.4.3 测试二: 1.4.4 测试三: 1.4.5 小结 1.4. ...
- RHEL 6.5----haproxy实现负载均衡
主机名 IP master 192.168.30.130 node-1 192.168.30.131 node-2 192.168.30.132 在master上安装 [root@master ~]# ...
- javascript回调函数那些事~
什么是回调函数? 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方直 ...