篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发编程 - IO模型 - 1.io模型/2.阻塞io/3.非阻塞io/4.多路复用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行为会让有在原地等待的效果
2.阻塞io
server:
1 from socket import *
2 from threading import Thread
3
4 def communicate(conn):
5 while True:
6 try:
7 data = conn.recv(1024)
8 if not data: break
9 conn.send(data.upper())
10 except ConnectionResetError:
11 break
12
13 conn.close()
14
15
16
17 server = socket(AF_INET, SOCK_STREAM)
18 server.bind((‘127.0.0.1‘,8080))
19 server.listen(5)
20
21 while True:
22 print(‘starting...‘)
23 conn, addr = server.accept() # io 阻塞 os拿走了cpu
24 print(addr)
25
26 t=Thread(target=communicate,args=(conn,))
27 t.start()
28
29 server.close()
client:
1 from socket import *
2
3 client=socket(AF_INET,SOCK_STREAM)
4 client.connect((‘127.0.0.1‘,8080))
5
6
7 while True:
8 msg=input(‘>>: ‘).strip()
9 if not msg:continue
10 client.send(msg.encode(‘utf-8‘))
11 data=client.recv(1024)
12 print(data.decode(‘utf-8‘))
13
14 client.close()
3.非阻塞io:
自己监测io 遇到io 就切 并且把 单线程得效率提到最高
导致得问题:
1.当有数据来得时候,cpu 在做其他得事情,不会立即响应
2.服务端没有任何阻塞,说白了,就是死循环,cpu会一直运转,线程处于就绪状态,大量占用cpu ,做无用,这个线程会一直问cpu,有数据没,有数据没
不推荐使用
server:
1 from socket import *
2
3 server = socket(AF_INET, SOCK_STREAM)
4 server.bind((‘127.0.0.1‘,8083))
5 server.listen(5)
6 server.setblocking(False) # 默认True 阻塞
7 print(‘starting...‘)
8
9
10 rlist=[]
11 wlist=[]
12 while True:
13
14 try: # 服务端不停得建链接
15 conn, addr = server.accept()
16 rlist.append(conn)
17 print(rlist)
18 except BlockingIOError: # 没阻塞
19 # print(‘干其他的活‘)
20
21 #收消息
22 del_rlist = []
23 for conn in rlist:
24 try:
25 data=conn.recv(1024)
26 if not data:
27 del_rlist.append(conn)
28 continue
29 wlist.append((conn,data.upper()))
30 except BlockingIOError:
31 continue
32 except Exception:
33 conn.close()
34 del_rlist.append(conn)
35
36 #发消息
37 del_wlist=[]
38 for item in wlist:
39 try:
40 conn=item[0]
41 data=item[1]
42 conn.send(data) # send 在数据量 过大时 也会阻塞
43 del_wlist.append(item)
44 except BlockingIOError:
45 pass
46
47 for item in del_wlist:
48 wlist.remove(item)
49
50 for conn in del_rlist:
51 rlist.remove(conn)
52
53
54 server.close()
client:
1 from socket import *
2
3 client=socket(AF_INET,SOCK_STREAM)
4 client.connect((‘127.0.0.1‘,8083))
5
6
7 while True:
8 msg=input(‘>>: ‘).strip()
9 if not msg:continue
10 client.send(msg.encode(‘utf-8‘))
11 data=client.recv(1024)
12 print(data.decode(‘utf-8‘))
13
14 client.close()
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
server:
1 from socket import *
2 import select
3
4 server = socket(AF_INET, SOCK_STREAM)
5 server.bind((‘127.0.0.1‘,8083))
6 server.listen(5)
7 server.setblocking(False)
8 print(‘starting...‘)
9
10 rlist=[server,]
11 wlist=[]
12 wdata={}
13
14 while True:
15 rl,wl,xl=select.select(rlist,wlist,[],0.5) # [] 异常列表 每隔0.5s 问一次
16 print(‘rl‘,rl)
17 print(‘wl‘,wl)
18
19 for sock in rl:
20 if sock == server:
21 conn,addr=sock.accept()
22 rlist.append(conn)
23 else:
24 try:
25 data=sock.recv(1024)
26 if not data:
27 sock.close()
28 rlist.remove(sock)
29 continue
30 wlist.append(sock)
31 wdata[sock]=data.upper()
32 except Exception:
33 sock.close()
34 rlist.remove(sock)
35
36 for sock in wl:
37 data=wdata[sock]
38 sock.send(data)
39 wlist.remove(sock)
40 wdata.pop(sock)
41
42 server.close()
client:
1 from socket import *
2
3 client=socket(AF_INET,SOCK_STREAM)
4 client.connect((‘127.0.0.1‘,8083))
5
6
7 while True:
8 msg=input(‘>>: ‘).strip()
9 if not msg:continue
10 client.send(msg.encode(‘utf-8‘))
11 data=client.recv(1024)
12 print(data.decode(‘utf-8‘))
13
14 client.close()