我们在使用多线程并发处理IO操作时候,每个线程当发送一个请求之后,就得阻塞等待接受返回的数据,数据较少的时候,这样并发操作还行,但是当数据非常庞大的时候,等待时间就会非常漫长,那么我们可以使用单线程非阻塞,就是使用一个线程逐个发送每一个请求,不用等待数据的返回操作,然后全都发送完毕,在逐个的接受每一个请求返回的数据
其中会使用到select模块
select模块就是用于监听每一个请求对象的变化
其中有三个方法
select(rlist, wlist, xlist, timeout=None),其本质就是调用每一个socket对象中的fileno()函数进行监听
rlist 表示列表中的每一个对象都是服务端返回的数据变化的socket对象
wlist 列表中每一个对象表示与服务端连接成功之后的socket对象
xlist 列表表示出现错误的socket对象
timeout 表示隔多长时间检测一次,
注意 select使循环检测的,最多1024个socket对象poll方法,表示无限制socket对象,循环检测epoll 方法,表示无限制不循环检测
具体代码:
import socketimport selectsocket_list = []conn_list = []client1 = socket.socket()client1.setblocking(False)try:client1.connect(("", 80))except BlockingIOError:passsocket_list.append(client1)client2 = socket.socket()client2.setblocking(False)try:client2.connect(("",80))except BlockingIOError:passsocket_list.append(client2)conn_list.append(client1)conn_list.append(client2)while True:rlist,wlist,elist = select.select(socket_list,conn_list,[],0.05)for sk in wlist:sk.sendall(b"GET /s?wd=hello HTTP/1.0\r\nhost:\r\n\r\n")conn_list.remove(sk)for sk in rlist:data_list = []while True:try:data = sk.recv(8096)data_list.append(data)if not data:breakexcept BlockingIOError:breakret = b''.join(data_list)print(ret.decode("utf-8"))sk.close()socket_list.remove(sk)if not socket_list:break