selectors — 高階 I/O 多路複用

在 3.4 版本加入。

原始碼: Lib/selectors.py


引言

此模組基於 select 模組原語構建,允許進行高階且高效的 I/O 多路複用。除非使用者希望對所使用的作業系統級原語進行精確控制,否則建議使用此模組。

它定義了一個抽象基類 BaseSelector,以及幾種具體實現(KqueueSelectorEpollSelector…),可用於等待多個檔案物件的 I/O 就緒通知。在下文中,“檔案物件”指任何具有 fileno() 方法的物件,或原始檔案描述符。參見 檔案物件

DefaultSelector 是當前平臺上最有效實現的別名:這應該是大多數使用者的預設選擇。

備註

支援的檔案物件型別取決於平臺:在 Windows 上,支援套接字,但不支援管道;而在 Unix 上,兩者都支援(可能還支援其他一些型別,例如 FIFO 或特殊檔案裝置)。

參見

select

低階 I/O 多路複用模組。

可用性:非 WASI。

此模組在 WebAssembly 上不起作用或不可用。有關更多資訊,請參閱 WebAssembly 平臺

類層次結構

BaseSelector
+-- SelectSelector
+-- PollSelector
+-- EpollSelector
+-- DevpollSelector
+-- KqueueSelector

在下文中,events 是一個位掩碼,表示應在給定檔案物件上等待哪些 I/O 事件。它可以是以下模組常量的組合

常量

含義

selectors.EVENT_READ

可讀

selectors.EVENT_WRITE

可寫

class selectors.SelectorKey

SelectorKey 是一個 namedtuple,用於將檔案物件與其底層檔案描述符、選定的事件掩碼和附加資料關聯起來。它由幾個 BaseSelector 方法返回。

fileobj

已註冊的檔案物件。

fd

底層檔案描述符。

events

必須在此檔案物件上等待的事件。

data

與此檔案物件關聯的可選不透明資料:例如,這可以用於儲存每個客戶端的會話 ID。

class selectors.BaseSelector

BaseSelector 用於等待多個檔案物件上的 I/O 事件就緒。它支援檔案流注冊、登出,以及等待這些流上的 I/O 事件的方法,並帶有一個可選的超時。它是一個抽象基類,因此不能被例項化。請改用 DefaultSelector,或者如果您想專門使用某個實現,並且您的平臺支援它,則可以使用 SelectSelectorKqueueSelector 等。BaseSelector 及其具體實現支援 上下文管理器 協議。

abstractmethod register(fileobj, events, data=None)

註冊檔案物件以進行選擇,監控其 I/O 事件。

fileobj 是要監控的檔案物件。它可以是整數檔案描述符,也可以是具有 fileno() 方法的物件。events 是要監控的事件的位掩碼。data 是一個不透明物件。

這會返回一個新的 SelectorKey 例項,或者在事件掩碼或檔案描述符無效時引發 ValueError,或者在檔案物件已註冊時引發 KeyError

abstractmethod unregister(fileobj)

從選擇中登出檔案物件,將其從監控中移除。檔案物件應在關閉之前登出。

fileobj 必須是先前已註冊的檔案物件。

這會返回關聯的 SelectorKey 例項,或者在 fileobj 未註冊時引發 KeyError。如果 fileobj 無效(例如,它沒有 fileno() 方法或其 fileno() 方法返回無效值),它將引發 ValueError

modify(fileobj, events, data=None)

更改已註冊檔案物件的受監控事件或附加資料。

這等同於 BaseSelector.unregister(fileobj) 後跟 BaseSelector.register(fileobj, events, data),但可以更高效地實現。

這會返回一個新的 SelectorKey 例項,或者在事件掩碼或檔案描述符無效時引發 ValueError,或者在檔案物件未註冊時引發 KeyError

abstractmethod select(timeout=None)

等待直到某些已註冊的檔案物件變為就緒,或超時過期。

如果 timeout > 0,這指定了最長等待時間,以秒為單位。如果 timeout <= 0,呼叫將不會阻塞,並將報告當前就緒的檔案物件。如果 timeoutNone,呼叫將阻塞直到受監控的檔案物件變為就緒。

這會返回一個 (key, events) 元組列表,每個就緒檔案物件對應一個。

key 是與就緒檔案物件對應的 SelectorKey 例項。events 是此檔案物件上就緒事件的位掩碼。

備註

如果當前程序接收到訊號,此方法可能會在任何檔案物件變為就緒或超時過去之前返回:在這種情況下,將返回一個空列表。

3.5 版中變更: 如果訊號處理器沒有引發異常,當被訊號中斷時,選擇器現在會重新計算超時並重試(參見 PEP 475 以瞭解原理),而不是在超時前返回空事件列表。

close()

關閉選擇器。

必須呼叫此方法以確保釋放任何底層資源。選擇器一旦關閉就不應再使用。

get_key(fileobj)

返回與已註冊檔案物件關聯的鍵。

這會返回與此檔案物件關聯的 SelectorKey 例項,或者在檔案物件未註冊時引發 KeyError

abstractmethod get_map()

返回檔案物件到選擇器鍵的對映。

這會返回一個 Mapping 例項,將已註冊的檔案物件對映到其關聯的 SelectorKey 例項。

class selectors.DefaultSelector

預設選擇器類,使用當前平臺上最有效的實現。這應該是大多數使用者的預設選擇。

class selectors.SelectSelector

基於 select.select() 的選擇器。

class selectors.PollSelector

基於 select.poll() 的選擇器。

class selectors.EpollSelector

基於 select.epoll() 的選擇器。

fileno()

這會返回底層 select.epoll() 物件使用的檔案描述符。

class selectors.DevpollSelector

基於 select.devpoll() 的選擇器。

fileno()

這會返回底層 select.devpoll() 物件使用的檔案描述符。

在 3.5 版本加入。

class selectors.KqueueSelector

基於 select.kqueue() 的選擇器。

fileno()

這會返回底層 select.kqueue() 物件使用的檔案描述符。

示例

這是一個簡單的 echo 伺服器實現

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:
    events = sel.select()
    for key, mask in events:
        callback = key.data
        callback(key.fileobj, mask)