一、IO模型
IO模型就是解决IO问题的方式
IO指的是输入输出,输入输出设备的速度与CPU相比来说是非常慢的,比如recv,input等都是IO操作
IO操作的最大问题就是会阻塞程序执行
IO模型要解决的仅仅是网络IO操作
IO模型分类(5类):
1、阻塞IO
socket默认模块就是阻塞的
问题:同一时间只能服务一个客户端
解决方法一:多线程(优点:若并发量不高,效率是比较高的,因为每个客户端都有单独线程来处理。弊端:线程需要占用资源,不能无限去开线程)
解决方法二:多进程(优点:可以多个CPU并行处理。弊端:占用的资源非常大,一旦客户很多,速度就会变慢)
解决方法三:线程池(优点:保证了服务器正常运行,负责创建和销毁线程以及任务分配。弊端:并发量超出最大线程数量,会造成阻塞)
解决方法四:协程(优点:不需要创建线程,不需要再线程之间切换,没有数量限制。弊端:不能利用多核优势,单核处理器性能是有上限的,如果并发很大处理器速度就会变慢)
真正导致效率低的是阻塞问题,以上方法都没有真正的解决阻塞问题,只是避开了阻塞问题
2、非阻塞IO
遇到IO操作也不会阻塞,仍然会继续执行。即使遇到IO,CPU执行权也不会剥夺,程序效率会变更高。
3、IO多路复用*****
一些程序占用CPU太高,原因是需要无限的循环去向操作系统拿数据
IO多路复用也是单线程并发处理所有请求
与非阻塞不同之处是不需要频繁不断地发送系统调用,只要等到select选择准备就绪socket,然后进行处理
4、异步IO(爬虫阶段)
5、信号驱动(了解)
二、IO多路复用
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import socket 2 c = socket.socket() 3 c.connect(("127.0.0.1,8080)) 4 print("已连接") 5 6 while True: 7 msg = input(">>>").strip() 8 if not msg:continue 9 c.send(msg.encode("utf-8")) 10 11 data = c.recv(1024) 12 print(data.decode("utf-8"))
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import socket 2 import time 3 import select 4 s = socket.socket() 5 s.bind(("127.0.0.1",8080)) 6 s.listen() 7 8 r_list = [s] 9 w_list = [] 10 data_dic ={} 11 while True: 12 readables,writeables,_ = select.select(r_list,w_list,[]) 13 for i in readables: 14 if i ==s: 15 c,_ = i.accept() 16 r_list.append(c) 17 else: 18 try: 19 data = i.recv(1024) 20 if not data: 21 i.close() 22 r_list.remove(i) 23 continue 24 print(data) 25 w_list.append(i) 26 data_dic[i] =data 27 except ConnectionResetError: 28 i.close() 29 r_list.remove(i) 30 for i in writeables: 31 try: 32 i.send(data_dic[i].upper()) 33 except ConnectionResetError: 34 i.close() 35 finally: 36 data_dic.pop(i) 37 w_list.remove(i)
三、阻塞IO模型
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import socket 2 import os 3 c = socket.socket() 4 c.connect(("127.0.0.1",9999)) 5 print("connect...") 6 7 while True: 8 msg = "%s 发来问候"% os.getpid() 9 if not msg:continue 10 c.send(msg.encode("utf-8")) 11 data = c.recv(1024) 12 print(data.decode("utf-8"))
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import socket 2 from threading import Thread 3 s = socket.socket() 4 s.bind(("127.0.0.1",9999)) 5 s.listen 6 7 def talking(c): 8 while True: 9 try: 10 data = c.recv(1024) 11 print("recv...") 12 if not data: 13 c.close() 14 break 15 c.send(data.upper()) 16 except ConnectionResetError: 17 c.close() 18 break 19 while True: 20 c,addr = s.accept() 21 print("accept...") 22 t = Thread(target=talking,args=(c,)) 23 t.start()
四、非阻塞IO模型
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import socket 2 c = socket.socket() 3 c.connect(("127.0.0.1",9999)) 4 print("已连接") 5 6 while True: 7 msg = input(">>>").strip() 8 if not msg:continue 9 c.send(msg.encode("utf-8")) 10 data = c.recv(1024) 11 print(data.encode("utf-8"))
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import socket 2 s = socket.socket() 3 s.bind(("127.0.0.1",9999)) 4 s.listen() 5 s.setblocking(False) 6 7 cs = [] 8 send_cs = [] 9 10 while True: 11 try: 12 c,addr = s.accept() 13 print("run accept") 14 cs.append(c) 15 except BlockingIOError: 16 for c in cs[:]: 17 try: 18 data = c.recv(1024) 19 if not data: 20 c.close() 21 cs.remove(c) 22 print(data.decode("utf-8")) 23 send_cs.append((c,data)) 24 except BlockingIOError: 25 continue 26 except ConnectionResetError: 27 c.close() 28 cs.remove(c) 29 for item in send_cs[:]: 30 c,data = item 31 try: 32 c.send(data.upper()) 33 send_cs.remove(item) 34 except BlockingIOError: 35 c.close 36 except ConnectionResetError: 37 c.close() 38 send_cs.remove(item) 39 cs.remove(c)