常见的异步io模块asyncio、gevent、twisted、tornado
核心技术为select()和协程
异步io请求的本质则是【非阻塞Socket】+【IO多路复用】
协程在这里不是一个必须使用的技术,在使用select()事件驱动循环本身就可以达到单线程异步的效果
io协程在遇到阻塞时进行切换,其实现需要依赖select()事件循环进行切换
协程本质是一种上下文切换技术,通过生成器yield记录状态的特性来实现
r,w,e = select.select([rlist],[wlist],[error],timeout)
select:采用事件轮询方式,即在while True下不断轮询所有的socket,
某个socket有数据返回时通知用户进程,最大轮询事件为1024,可以跨平台,水平触发
poll:方式相同,没有最大轮询事件数量限制
epoll:方式不同,比如100个连接,有两个活跃了,epoll会告诉用户这两个两个活跃了,直接取就ok了,而select是循环一遍。
select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。
如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO
的web server性能更好,可能延迟还更大。
1 import socket,select 2 3 socket_list = [ 4 (‘www.baidu.com‘,80), 5 (‘202.89.233.100‘,80), 6 (‘101.37.225.65‘,80), 7 ] 8 soc_list = [] 9 conn_list=[] 10 for s in socket_list: 11 c = socket.socket() 12 c.setblocking(False) 13 try: 14 c.connect(s) 15 except Exception as e: 16 pass 17 soc_list.append(c) 18 conn_list.append(c) 19 print(soc_list) 20 while True: 21 r,w,error = select.select(soc_list,conn_list,[]) 22 for i in soc_list: 23 try: 24 while True: 25 data = i.sock.recv(8096) 26 print(i) 27 if not data: 28 soc_list.remove(i) 29 except Exception as e: 30 pass 31 32 for i in conn_list: 33 i.sendall("""GET /index HTTP/1.0\r\nHost: www.baidu.com\r\n\r\n""") 34 conn_list.remove(i)