這篇文章我們從 socket 程式設計的範例來看看 Python 非同步框架是如何運作的,需要了解下簡單的 socket 程式設計以及 Linux 提供的 I/O 復用機制。 Python 非同步框架也是基於作業系統底層提供的 I/O 重複使用機制來實現的,例如 linux 下可以使用 select/poll/epoll 等。我們先來看個簡單的 python socket server 例子,Python 程式碼使用 Python3,確保可以使用 selectors 模組。
一個實例
import socket HOST = 'localhost' # The remote host PORT = 8888 # Arbitrary non-privileged port with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind((HOST, PORT)) s.listen(50) while True: conn, addr = s.accept() print('Connected by', addr) with conn: while 1: data = conn.recv(1024) if not data: break conn.sendall(data)
我們下邊用一個golang 的tcp client 測試下它:
package main import ( "fmt" "net" "os" "sync" ) func sendMessage(msg string) error { conn, err := net.Dial("tcp", "localhost:8888") if err != nil { return fmt.Errorf("error: %v", err) } defer conn.Close() _, err = conn.Write([]byte("hello")) if err != nil { return fmt.Errorf("error: %v", err) } reply := make([]byte, 1024) _, err = conn.Read(reply) if err != nil { println("Write to server failed:", err.Error()) os.Exit(1) } println("reply from server=", string(reply)) return nil } func main() { var wg sync.WaitGroup nbGoroutines := 20 wg.Add(nbGoroutines) for k := 0; k < nbGoroutines; k++ { go func() { err := sendMessage("hello") if err != nil { fmt.Printf("fail: %v\n", err) } wg.Done() }() } wg.Wait() }
使用go 執行它可以看到輸出。
接下來我們使用 python3 提供的 selectros 來改造它,這個模組封裝了作業系統底層提供的 I/O 復用機制,例如 linux 上使用了 epoll。透過 I/O 重複使用機制我們可以監聽多個檔案描述符的可讀寫事件並且註冊回呼函數,擁有更好的並發效能。先看 python3 的 selectors 文件給的例子
import selectors import socket sel = selectors.DefaultSelector() def accept(sock, mask): conn, addr = sock.accept() # Should be ready print('accepted', conn, 'from', addr) conn.setblocking(False) sel.register(conn, selectors.EVENT_READ, read) def read(conn, mask): data = conn.recv(1000) # Should be ready if data: print('echoing', repr(data), 'to', conn) conn.send(data) # Hope it won't block else: print('closing', conn) sel.unregister(conn) conn.close() sock = socket.socket() sock.bind(('localhost', 1234)) sock.listen(100) sock.setblocking(False) sel.register(sock, selectors.EVENT_READ, accept) while True: # 这其实就是通常在异步框架中所说的 event loop 啦 events = sel.select() for key, mask in events: callback = key.data callback(key.fileobj, mask)
我們來運行下這個 使用了 seelctors I/O 復用機制的 tcp echo server 看下輸出結果。
到這裡就差不多了,我們再繼續執行 go 寫的 tcp client 來測試它看結果。
在後邊教學中我們將使用python 的coroutine 而不是回呼函數來改造這個例子,這樣一來我們就能使用async/await 來運行它了
以上是web前端三大主流框架之Python異步框架如何運作?的詳細內容。更多資訊請關注PHP中文網其他相關文章!