select --- 等待一組串流上的事件

此模組提供函式,可有效率地等待直到一個或多個 串流(實作串流協定的類檔案物件,例如 socket、UART 以及其他 I/O 物件)就緒可進行讀取或寫入,而非在單一物件上忙碌等待或封鎖。

poll 物件是建議使用的介面:它可擴展至大量串流,且透過 poll.ipoll() 使用時不需配置記憶體。模組層級的 select() 函式則是效率較低的相容性介面。

使用 poll 物件的範例::

import select

poller = select.poll()
poller.register(uart, select.POLLIN)

while True:
    # Wait up to 1000 ms for the UART to have data.
    for obj, event in poller.poll(1000):
        if event & select.POLLIN:
            print(obj.read())

使用模組層級 select() 函式的範例::

import select

# Wait up to 1 second for the socket to become readable.
rlist, wlist, xlist = select.select([sock], [], [], 1.0)
if rlist:
    data = sock.recv(100)

函式

select.select(rlist: List, wlist: List, xlist: List, timeout: float | None = None) Tuple[List, List, List]

等待直到一個或多個給定的串流物件就緒,或直到 timeout 逾時。

  • rlist 是要監看其可讀性的物件清單。

  • wlist 是要監看其可寫性的物件清單。

  • xlist 是要監看其錯誤或斷線狀況的物件清單。

  • timeout 是最長等待時間,單位為秒(接受浮點數)。若省略或為 None,呼叫會無限期封鎖;0 則立即回傳(非封鎖式輪詢)。

回傳一個由清單組成的 3 元組 (rlist, wlist, xlist)。每個回傳的清單分別是對應輸入清單的子集,包含已就緒可讀取、已就緒可寫入,或發出錯誤/斷線訊號的物件。若 timeout 過去而沒有任何項目就緒,則三個清單皆為空。

此函式的效率低於 poll(它在每次呼叫時都會重建其內部輪詢集);在可能的情況下請改用 poll

常數

select.POLLIN: int

串流有資料可供讀取。

select.POLLOUT: int

串流可接受更多資料寫入。

select.POLLERR: int

串流上發生了錯誤狀況。這是一個 非主動請求的 事件:即使未在 eventmask 中請求,poll.poll() / poll.ipoll() 也會回報它,且將它作為輸入 eventmask 傳入是無效的。

select.POLLHUP: int

串流已斷線/中斷連線。這是一個 非主動請求的 事件:即使未在 eventmask 中請求,poll.poll() / poll.ipoll() 也會回報它,且將它作為輸入 eventmask 傳入是無效的。

類別

class select.poll

建立一個輪詢物件,它維護一組已註冊的串流(或任何公開串流協定的物件),並有效率地等待直到其中一個或多個變為可讀、可寫,或發出例外狀況訊號。

串流以 register() 加入、以 unregister() 移除,要監看的事件集可用 modify() 變更。設定完成後,呼叫 poll() 以封鎖直到有項目就緒(或逾時),或呼叫 ipoll() 取得不需配置記憶體、以迭代器為基礎的變體。

register(obj: Any, eventmask: int = select.POLLIN | select.POLLOUT) None

註冊 串流 obj 以進行輪詢,監看由 eventmask(下列各項的邏輯 OR)所指定的事件:

eventmask 預設為 select.POLLIN | select.POLLOUT

select.POLLHUPselect.POLLERR 在輸入 eventmask 中是 無效的 -- 它們是非主動請求的事件,無論是否被請求,都會由 poll() / ipoll() 回報(這與 POSIX 語意一致)。

對同一個 obj 多次呼叫此方法是可以的:後續呼叫會更新 obj 的事件遮罩,其行為如同 modify()

unregister(obj: Any) None

從已註冊串流集中移除 obj。取消註冊一個目前未註冊的 obj 並不會發生錯誤(在此情況下該呼叫沒有作用)。

modify(obj: Any, eventmask: int) None

將一個已註冊的 obj 的事件遮罩變更為 eventmask。若 obj 未註冊,則引發帶有 errno.ENOENTOSError

poll(timeout: int = -1, /) List[Tuple]

封鎖直到至少有一個已註冊串流就緒或發出例外狀況訊號,然後回傳已觸發的串流清單。

timeout 是最長等待時間,單位為 毫秒。若省略或為 -1,呼叫會無限期封鎖;0 則立即回傳(非封鎖式輪詢)。

回傳一個由 (obj, event, ...) 元組組成的清單,每個觸發的串流對應一個。obj 是已註冊的串流,event 則是所發生的 select.POLLIN / select.POLLOUT / select.POLLERR / select.POLLHUP 旗標的位元 OR。每個元組可能包含額外的實作定義元素,因此請勿假設其長度恰為 2。若 timeout 過去而沒有任何項目就緒,則回傳一個空清單。

select.POLLHUPselect.POLLERR 可能在任何時候被回傳(即使未被請求),且必須加以處理 -- 通常是取消註冊並關閉受影響的串流 -- 否則後續呼叫會持續為該串流立即回傳並設定這些旗標。

任何待處理的已排程回呼函式,保證會在進入輪詢迴圈之前執行。

與 CPython 的差異

如上所述,回傳的元組可能包含超過 2 個元素。

ipoll(timeout: int = -1, flags: int = 0, /) Iterator[Tuple]

poll() 類似,但它不會建立清單,而是回傳一個迭代器,每次產出一個 (obj, event, ...) 元組。這避免了每次呼叫時的記憶體配置,對非同步 I/O 排程器而言相當重要。

所產出的元組為 被呼叫端所擁有:它會在下一次迭代時被重複使用(覆寫),因此其內容必須在迴圈主體內消耗完畢,且不得儲存對它的參考。

timeout 的意義與 poll() 相同。若 flags1,則使用單次(one-shot)行為:事件已觸發的串流,其事件遮罩會自動被清除(等同於 poll.modify(obj, 0)),因此在以 modify() 重新設定其遮罩之前,不會再為它回報任何事件。

任何待處理的已排程回呼函式,保證會在進入輪詢迴圈之前執行。

與 CPython 的差異

此方法是 MicroPython 的擴充功能。