一、IO模型介绍
1、阻塞与非阻塞指的是程序的两种运行状态
阻塞:遇到IO就发生阻塞,程序一旦遇到阻塞操作就会停在原地,并且立刻释放CPU资源
非阻塞(就绪态或运行态):没有遇到IO操作,或者通过某种手段让程序即便是遇到IO操作也不会停在原地,执行其他操作,力求尽可能多的占有CPU
2、同步与异步指的是提交任务的两种方式:
同步调用:提交完任务后,就在原地等待,直到任务运行完毕后,拿到任务的返回值,才继续执行下一行代码
异步调用:当进程执行到一个IO(等待外部数据)的时候,不需要等待,待数据接收成功后,再回来处理。
1.io模型 提交任务得方式: 同步:提交完任务,等结果,执行下一个任务 异步:提交完,接着执行,异步 + 回调 异步不等结果,提交完任务,任务执行完后,会自动触发回调函数 同步不等于阻塞: 阻塞:遇到io,自己不处理,os会抢走cpu ,解决办法:监测到io,gevent切换到其他任务,类似欺骗os 非阻塞:cpu 运行 IO分类: 1.阻塞IO blocking IO 2.非阻塞IO nonblocking IO 3.IO多路复用 IO multiplexing 4.信号驱动IO signal driven IO 用得比较少 5.异步IO asynchronous IO 遇到IO: 卡 网络IO: 原地阻塞 1.server端什么样得操作属于IO行为 # accept recv send 阻塞操作 accept recv 明显得等 send 不会明显等,但是一种io行为 2.为什么IO行为会让有在原地等待的效果 3.非阻塞io: 自己监测io 遇到io 就切 并且把 单线程得效率提到最高 导致得问题: 1.当有数据来得时候,cpu 在做其他得事情,不会立即响应 2.服务端没有任何阻塞,说白了,就是死循环,cpu会一直运转,线程处于就绪状态,大量占用cpu ,做无用,这个线程会一直问cpu,有数据没,有数据没 不推荐使用 4.多路复用io: wait copy 还多了select 中间有个中介存在,帮问os 有没有数据 但是如果中介 只有1个 效率不如 阻塞效率 但是如果中介监测多个套接字 ,性能高就是:同时监测多个套接字问os系统好了没 就比阻塞io效率高 监测套接字得io行为 服务端得套接字有几类:server conn select 阻塞io 效率高 比非阻塞io 效率也高 ,一直做无用 总结: 同时监测多个套接字 列表 循环 慢 假设列表数据多,循环 效率低 监测套接字好没好 从头到尾 循环1遍 select 列表循环 效率低 poll 可接收得列表数据多 效率也不高 epoll 效率最高得 异步操作 每个套接字身上绑定个回调函数,谁好了谁触发回调,(就不用去遍历了 效率低) epoll windows 不支持 linux 支持 selectors 模块 自动根据操作系统选择 poll epoll
二、阻塞IO模型
默认情况下,所有的socket都是blocking模型,
实际上,除非特别指定,几乎所有的IO接口 ( 包括socket接口 ) 都是阻塞型的。
这给网络编程带来了一个很大的问题,如在调用recv(1024)的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。
blocking IO的特点就是在IO执行的两个阶段(等待数据和拷贝数据两个阶段)都被block了。
三、非阻塞IO模型
在非阻塞式IO中,用户进程其实是需要不断的主动询问kernel数据准备好了没有。
from socket import * server = socket(AF_INET, SOCK_STREAM) server.bind(('127.0.0.1',8083)) server.listen(5) server.setblocking(False) print('starting...') rlist=[] wlist=[] while True: try: conn, addr = server.accept() rlist.append(conn) print(rlist) except BlockingIOError: # print('干其他的活') #收消息 del_rlist = [] for conn in rlist: try: data=conn.recv(1024) if not data: del_rlist.append(conn) continue wlist.append((conn,data.upper())) except BlockingIOError: continue except Exception: conn.close() del_rlist.append(conn) #发消息 del_wlist=[] for item in wlist: try: conn=item[0] data=item[1] conn.send(data) del_wlist.append(item) except BlockingIOError: pass for item in del_wlist: wlist.remove(item) for conn in del_rlist: rlist.remove(conn) server.close()