python協程和異步IO
1.並發、並行、同步、異步、阻塞、非阻塞
並發:是指在同一個時間段內,有幾個程序都處於啟動運行到運行結束之間
並行:在同一個時間點上,有幾個程序同時運行
同步:當一個同步操作發出去後,調用者一直等待返回消息結果,才能進行後續的操作 比如操作文件 打開文件 讀取文件 都是同步操作
異步: 當一個異步操作發出去後,調用者不能立刻得到消息結果 創建線程 都是異步操作
阻塞:調用結果返回之前,當前線程會被掛起來,一直處於等待消息通知,不能執行其他業務
非阻塞:調用結果返回之前,該函數不會阻塞當前線程 而立刻返回
2.IO多路復用select、poll、epoll
select
它通過一個select()系統調用來監視多個文件描述符,當select()返回後,該數組中就緒的文件描述符會被內核修改標誌位,使進程能夠獲得這些文件描述符,從 而進行後續的修改
缺點:單個進程能夠監視的文件描述符的數量存在最大限制 一般1024
poll
本質跟select()沒有區別 但是poll沒有限制,使用的是鏈表存儲
epoll
epoll同樣只告知那些就緒的文件描述符,而且當我們調用epoll_wait()獲得就緒文件描述符時,返回的不是實際的描述符,而是一個代表就緒描述符數量的 值,你只需要去epoll指定的一個數組中依次取得相應數量的文件描述符即可,這裏也使用了內存映射(mmap)技術,這樣便徹底省掉了這些文件描述符 在系統調用時復制的開銷。
另一個本質的改進在於epoll采用基於事件的就緒通知方式。在select/poll中,進程只有在調用一定的方法後,內核才對所有監視的文件描述符進行掃描, 而poll事先通過epoll_ctl()來註冊一個文件描述符,一旦基於某個文件描述符就緒時,內核會采用類似callback的回調機制,迅速激活這個文件描 述符,當進程調用epoll_wait()時便得到通知。
epoll實列
1 import selectors,socket 2 def accept(sock, mask): 3 conn, addr = sock.accept()View Code4 print(‘accepted{}from{}‘.format(conn,addr)) 5 conn.setblocking(False) 6 sel.register(conn,selectors.EVENT_READ, read) 7 8 def read(conn, mask): 9 data = conn.recv(1024) 10 if data: 11 print(‘echoing{}to{}‘.format(repr(data),conn)) 12 else: 13 print(‘closing‘,conn) 14 sel.unregister(conn) 15 conn.close() 16 sel = selectors.DefaultSelector() 17 server = socket.socket() 18 server.bind((‘localhost‘, 9999)) 19 server.listen(500) 20 server.setblocking(False) 21 sel.register(server, selectors.EVENT_READ, accept) #註冊事件,只要來一個連接就調accept這個函數, 22 23 while True: 24 events = sel.select()#這個select,看起來是select,有可能調用的是epoll,看你操作系統是Windows的還是Linux的 25 #默認阻塞,有活動連接就返回活動連接列表 26 print(‘事件‘,events) 27 28 for key,mask in events: 29 callback = key.data 30 callable(key.fileobj, mask)
客戶端
import socket,sys server_address = (‘localhost‘, 9999) # 創建100個 TCP/IP socket實例 socks = [ socket.socket(socket.AF_INET, socket.SOCK_STREAM) for i in range(100)] # 連接服務端 print(‘connecting to %s port %s‘ % server_address) for s in socks: s.connect(server_address) s.send(b‘kehuduan‘) data = s.recv(1024) print(‘服務端回來的數據{}‘.format(data)) if not data: print(‘連接失敗‘) s.close()
python協程和異步IO