1. 程式人生 > >python協程和異步IO

python協程和異步IO

block 註冊事件 %s close 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()
4 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)
View Code

  客戶端

    

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(bkehuduan)

    data = s.recv(1024)
    print(服務端回來的數據{}.format(data))
    if not data:
        print(連接失敗)
        s.close()

python協程和異步IO