select --- 等待 I/O 完成?


該模塊提供了對 select()poll() 函數的訪(fǎng)問(wèn),這些函數在大多數操作系統中是可用的。在 Solaris 及其衍生版本上可用 devpoll(),在 Linux 2.5+ 上可用 epoll(),在大多數 BSD 上可用 kqueue()。注意,在 Windows 上,本模塊僅適用于套接字;在其他操作系統上,本模塊也適用于其他文件類(lèi)型(特別地,在 Unix 上也適用于管道)。本模塊不能用于常規文件,不能檢測出(自上次讀取文件后)文件是否有新數據寫(xiě)入。

備注

selectors 模塊是在 select 模塊原型的基礎上進(jìn)行高級且高效的 I/O 復用。推薦用戶(hù)改用 selectors 模塊,除非用戶(hù)希望對 OS 級的函數原型進(jìn)行精確控制。

該模塊定義以下內容:

exception select.error?

一個(gè)被棄用的 OSError 的別名。

在 3.3 版更改: 根據 PEP 3151,這個(gè)類(lèi)是 OSError 的別名。

select.devpoll()?

(僅支持 Solaris 及其衍生版本)返回一個(gè) /dev/poll 輪詢(xún)對象,請參閱下方 /dev/poll 輪詢(xún)對象 獲取 devpoll 對象所支持的方法。

devpoll() 對象與實(shí)例化時(shí)允許的文件描述符數量有關(guān),如果在程序中降低了此數值,devpoll() 調用將失敗。如果程序提高了此數值,devpoll() 可能會(huì )返回一個(gè)不完整的活動(dòng)文件描述符列表。

新的文件描述符是 不可繼承的。

3.3 新版功能.

在 3.4 版更改: 新的文件描述符現在是不可繼承的。

select.epoll(sizehint=- 1, flags=0)?

(僅支持 Linux 2.5.44 或更高版本)返回一個(gè) edge poll 對象,該對象可作為 I/O 事件的邊緣觸發(fā)或水平觸發(fā)接口。

sizehint 指示 epoll 預計需要注冊的事件數。它必須為正數,或為 -1 以使用默認值。它僅在 epoll_create1() 不可用的舊系統上會(huì )被用到,其他情況下它沒(méi)有任何作用(盡管仍會(huì )檢查其值)。

flags 已經(jīng)棄用且完全被忽略。但是,如果提供該值,則它必須是 0select.EPOLL_CLOEXEC,否則會(huì )拋出 OSError 異常。

請參閱下方 邊緣觸發(fā)和水平觸發(fā)的輪詢(xún) (epoll) 對象 獲取 epoll 對象所支持的方法。

epoll 對象支持上下文管理器:當在 with 語(yǔ)句中使用時(shí),新建的文件描述符會(huì )在運行至語(yǔ)句塊結束時(shí)自動(dòng)關(guān)閉。

新的文件描述符是 不可繼承的。

在 3.3 版更改: 增加了 flags 參數。

在 3.4 版更改: 增加了對 with 語(yǔ)句的支持。新的文件描述符現在是不可繼承的。

3.4 版后已移除: flags 參數?,F在默認采用 select.EPOLL_CLOEXEC 標志。使用 os.set_inheritable() 來(lái)讓文件描述符可繼承。

select.poll()?

(部分操作系統不支持)返回一個(gè) poll 對象,該對象支持注冊和注銷(xiāo)文件描述符,支持對描述符進(jìn)行輪詢(xún)以獲取 I/O 事件。請參閱下方 Poll 對象 獲取 poll 對象所支持的方法。

select.kqueue()?

(僅支持 BSD)返回一個(gè)內核隊列對象,請參閱下方 Kqueue 對象 獲取 kqueue 對象所支持的方法。

新的文件描述符是 不可繼承的。

在 3.4 版更改: 新的文件描述符現在是不可繼承的。

select.kevent(ident, filter=KQ_FILTER_READ, flags=KQ_EV_ADD, fflags=0, data=0, udata=0)?

(僅支持 BSD)返回一個(gè)內核事件對象,請參閱下方 Kevent 對象 獲取 kevent 對象所支持的方法。

select.select(rlist, wlist, xlist[, timeout])?

這是一個(gè)明白直觀(guān)的 Unix select() 系統調用接口。 前三個(gè)參數是由‘可等待對象’組成的序列:可以是代表文件描述符的整數,或是帶有名為 fileno() 的返回這樣的整數的無(wú)形參方法的對象:

  • rlist:等待,直到可以開(kāi)始讀取

  • wlist:等待,直到可以開(kāi)始寫(xiě)入

  • xlist:等待“異常情況”(請參閱當前系統的手冊,以獲取哪些情況稱(chēng)為異常情況)

允許空的可迭代對象,但是否接受三個(gè)空的可迭代對象則取決于具體平臺。 (已知在 Unix 上可行但在 Windows 上不可行。) 可選的 timeout 參數以一個(gè)浮點(diǎn)數表示超時(shí)秒數。 當省略 timeout 參數時(shí)該函數將阻塞直到至少有一個(gè)文件描述符準備就緒。 超時(shí)值為零表示執行輪詢(xún)且永不阻塞。

返回值是三個(gè)列表,包含已就緒對象,返回的三個(gè)列表是前三個(gè)參數的子集。當超時(shí)時(shí)間已到且沒(méi)有文件描述符就緒時(shí),返回三個(gè)空列表。

可迭代對象中可接受的對象類(lèi)型有 Python 文件對象 (例如 sys.stdin 以及 open()os.popen() 所返回的對象),由 socket.socket() 返回的套接字對象等。 你也可以自定義一個(gè) wrapper 類(lèi),只要它具有適當的 fileno() 方法(該方法要確實(shí)返回一個(gè)文件描述符,而不能只是一個(gè)隨機整數)。

備注

Windows 上不接受文件對象,但接受套接字。在 Windows 上,底層的 select() 函數由 WinSock 庫提供,且不處理不是源自 WinSock 的文件描述符。

在 3.5 版更改: 現在,當本函數被信號中斷時(shí),重試超時(shí)將從頭開(kāi)始計時(shí),不會(huì )拋出 InterruptedError 異常。除非信號處理程序拋出異常(相關(guān)原理請參閱 PEP 475)。

select.PIPE_BUF?

當一個(gè)管道已經(jīng)被 select()、poll() 或本模塊中的某個(gè)接口報告為可寫(xiě)入時(shí),可以在不阻塞該管道的情況下寫(xiě)入的最小字節數。它不適用于套接字等其他類(lèi)型的文件類(lèi)對象。

POSIX 上須保證該值不小于 512。

可用性: Unix

3.2 新版功能.

/dev/poll 輪詢(xún)對象?

Solaris 及其衍生版本具備 /dev/poll。select() 復雜度為 O(最高文件描述符),poll() 為 O(文件描述符數量),而 /dev/poll 為 O(活動(dòng)的文件描述符)。

/dev/poll 的行為與標準 poll() 對象十分類(lèi)似。

devpoll.close()?

關(guān)閉輪詢(xún)對象的文件描述符。

3.4 新版功能.

devpoll.closed?

如果輪詢(xún)對象已關(guān)閉,則返回 True。

3.4 新版功能.

devpoll.fileno()?

返回輪詢(xún)對象的文件描述符對應的數字。

3.4 新版功能.

devpoll.register(fd[, eventmask])?

在輪詢(xún)對象中注冊文件描述符。這樣,將來(lái)調用 poll() 方法時(shí)將檢查文件描述符是否有未處理的 I/O 事件。fd 可以是整數,也可以是帶有 fileno() 方法的對象(該方法返回一個(gè)整數)。文件對象已經(jīng)實(shí)現了 fileno(),因此它們也可以用作參數。

eventmask 是可選的位掩碼,用于指定要檢查的事件類(lèi)型。這些常量與 poll() 對象所用的相同。本參數的默認值是常量 POLLIN、POLLPRIPOLLOUT 的組合。

警告

注冊已注冊過(guò)的文件描述符不會(huì )報錯,但是結果是不確定的。正確的操作是先注銷(xiāo)或直接修改它。與 poll() 相比,這是一個(gè)重要的區別。

devpoll.modify(fd[, eventmask])?

此方法先執行 unregister() 后執行 register()。直接執行此操作效率(稍微)高一些。

devpoll.unregister(fd)?

刪除輪詢(xún)對象正在跟蹤的某個(gè)文件描述符。與 register() 方法類(lèi)似,fd 可以是整數,也可以是帶有 fileno() 方法的對象(該方法返回一個(gè)整數)。

嘗試刪除從未注冊過(guò)的文件描述符將被安全地忽略。

devpoll.poll([timeout])?

輪詢(xún)已注冊的文件描述符的集合,并返回一個(gè)列表,列表可能為空,也可能有多個(gè) (fd, event) 二元組,其中包含了要報告事件或錯誤的描述符。fd 是文件描述符,event 是一個(gè)位掩碼,表示該描述符所報告的事件 --- POLLIN 表示可以讀取,POLLOUT 表示該描述符可以寫(xiě)入,依此類(lèi)推??樟斜肀硎菊{用超時(shí),沒(méi)有任何文件描述符報告事件。如果指定了 timeout,它將指定系統等待事件時(shí),等待多長(cháng)時(shí)間后返回(以毫秒為單位)。如果 timeout 為空,-1 或 None,則本調用將阻塞,直到輪詢(xún)對象發(fā)生事件為止。

在 3.5 版更改: 現在,當本函數被信號中斷時(shí),重試超時(shí)將從頭開(kāi)始計時(shí),不會(huì )拋出 InterruptedError 異常。除非信號處理程序拋出異常(相關(guān)原理請參閱 PEP 475)。

邊緣觸發(fā)和水平觸發(fā)的輪詢(xún) (epoll) 對象?

https://linux.die.net/man/4/epoll

eventmask

常量

含意

EPOLLIN

可讀

EPOLLOUT

可寫(xiě)

EPOLLPRI

緊急數據讀取

EPOLLERR

在關(guān)聯(lián)的文件描述符上有錯誤情況發(fā)生

EPOLLHUP

關(guān)聯(lián)的文件描述符已掛起

EPOLLET

設置觸發(fā)方式為邊緣觸發(fā),默認為水平觸發(fā)

EPOLLONESHOT

設置 one-shot 模式。觸發(fā)一次事件后,該描述符會(huì )在輪詢(xún)對象內部被禁用。

EPOLLEXCLUSIVE

當已關(guān)聯(lián)的描述符發(fā)生事件時(shí),僅喚醒一個(gè) epoll 對象。默認(如果未設置此標志)是喚醒所有輪詢(xún)該描述符的 epoll 對象。

EPOLLRDHUP

流套接字的對側關(guān)閉了連接或關(guān)閉了寫(xiě)入到一半的連接。

EPOLLRDNORM

等同于 EPOLLIN

EPOLLRDBAND

可以讀取優(yōu)先數據帶。

EPOLLWRNORM

等同于 EPOLLOUT

EPOLLWRBAND

可以寫(xiě)入優(yōu)先級數據。

EPOLLMSG

忽略

3.6 新版功能: 增加了 EPOLLEXCLUSIVE。僅支持 Linux Kernel 4.5 或更高版本。

epoll.close()?

關(guān)閉用于控制 epoll 對象的文件描述符。

epoll.closed?

如果 epoll 對象已關(guān)閉,則返回 True。

epoll.fileno()?

返回文件描述符對應的數字,該描述符用于控制 epoll 對象。

epoll.fromfd(fd)?

根據給定的文件描述符創(chuàng )建 epoll 對象。

epoll.register(fd[, eventmask])?

在 epoll 對象中注冊一個(gè)文件描述符。

epoll.modify(fd, eventmask)?

修改一個(gè)已注冊的文件描述符。

epoll.unregister(fd)?

從 epoll 對象中刪除一個(gè)已注冊的文件描述符。

在 3.9 版更改: 此方法不會(huì )再忽略 EBADF 錯誤。

epoll.poll(timeout=None, maxevents=- 1)?

等待事件發(fā)生,timeout 是浮點(diǎn)數,單位為秒。

在 3.5 版更改: 現在,當本函數被信號中斷時(shí),重試超時(shí)將從頭開(kāi)始計時(shí),不會(huì )拋出 InterruptedError 異常。除非信號處理程序拋出異常(相關(guān)原理請參閱 PEP 475)。

Poll 對象?

大多數 Unix 系統支持 poll() 系統調用,為服務(wù)器提供了更好的可伸縮性,使服務(wù)器可以同時(shí)服務(wù)于大量客戶(hù)端。poll() 的伸縮性更好,因為該調用內部?jì)H列出所關(guān)注的文件描述符,而 select() 會(huì )構造一個(gè) bitmap,在其中將所關(guān)注的描述符所對應的 bit 打開(kāi),然后重新遍歷整個(gè) bitmap。因此 select() 復雜度是 O(最高文件描述符),而 poll() 是 O(文件描述符數量)。

poll.register(fd[, eventmask])?

在輪詢(xún)對象中注冊文件描述符。這樣,將來(lái)調用 poll() 方法時(shí)將檢查文件描述符是否有未處理的 I/O 事件。fd 可以是整數,也可以是帶有 fileno() 方法的對象(該方法返回一個(gè)整數)。文件對象已經(jīng)實(shí)現了 fileno(),因此它們也可以用作參數。

eventmask 是可選的位掩碼,用于指定要檢查的事件類(lèi)型,它可以是常量 POLLIN、POLLPRIPOLLOUT 的組合,如下表所述。如果未指定本參數,默認將會(huì )檢查所有 3 種類(lèi)型的事件。

常量

含意

POLLIN

有要讀取的數據

POLLPRI

有緊急數據需要讀取

POLLOUT

準備輸出:寫(xiě)不會(huì )阻塞

POLLERR

某種錯誤條件

POLLHUP

掛起

POLLRDHUP

流套接字的對側關(guān)閉了連接,或關(guān)閉了寫(xiě)入到一半的連接

POLLNVAL

無(wú)效的請求:描述符未打開(kāi)

注冊已注冊過(guò)的文件描述符不會(huì )報錯,且等同于只注冊一次該描述符。

poll.modify(fd, eventmask)?

修改一個(gè)已注冊的文件描述符,等同于 register(fd, eventmask)。嘗試修改未注冊的文件描述符會(huì )拋出 OSError 異常,錯誤碼為 ENOENT。

poll.unregister(fd)?

刪除輪詢(xún)對象正在跟蹤的某個(gè)文件描述符。與 register() 方法類(lèi)似,fd 可以是整數,也可以是帶有 fileno() 方法的對象(該方法返回一個(gè)整數)。

嘗試刪除從未注冊過(guò)的文件描述符會(huì )拋出 KeyError 異常。

poll.poll([timeout])?

輪詢(xún)已注冊的文件描述符的集合,并返回一個(gè)列表,列表可能為空,也可能有多個(gè) (fd, event) 二元組,其中包含了要報告事件或錯誤的描述符。fd 是文件描述符,event 是一個(gè)位掩碼,表示該描述符所報告的事件 --- POLLIN 表示可以讀取,POLLOUT 表示該描述符可以寫(xiě)入,依此類(lèi)推??樟斜肀硎菊{用超時(shí),沒(méi)有任何文件描述符報告事件。如果指定了 timeout,它將指定系統等待事件時(shí),等待多長(cháng)時(shí)間后返回(以毫秒為單位)。如果 timeout 為空、負數 或 None,則本調用將阻塞,直到輪詢(xún)對象發(fā)生事件為止。

在 3.5 版更改: 現在,當本函數被信號中斷時(shí),重試超時(shí)將從頭開(kāi)始計時(shí),不會(huì )拋出 InterruptedError 異常。除非信號處理程序拋出異常(相關(guān)原理請參閱 PEP 475)。

Kqueue 對象?

kqueue.close()?

關(guān)閉用于控制 kqueue 對象的文件描述符。

kqueue.closed?

如果 kqueue 對象已關(guān)閉,則返回 True。

kqueue.fileno()?

返回文件描述符對應的數字,該描述符用于控制 epoll 對象。

kqueue.fromfd(fd)?

根據給定的文件描述符創(chuàng )建 kqueue 對象。

kqueue.control(changelist, max_events[, timeout]) eventlist?

Kevent 的低級接口

  • changelist 必須是一個(gè)可迭代對象,迭代出 kevent 對象,否則置為 None。

  • max_events 必須是 0 或一個(gè)正整數。

  • timeout 單位為秒(一般為浮點(diǎn)數),默認為 None,即永不超時(shí)。

在 3.5 版更改: 現在,當本函數被信號中斷時(shí),重試超時(shí)將從頭開(kāi)始計時(shí),不會(huì )拋出 InterruptedError 異常。除非信號處理程序拋出異常(相關(guān)原理請參閱 PEP 475)。

Kevent 對象?

https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2

kevent.ident?

用于區分事件的標識值。其解釋取決于篩選器,但該值通常是文件描述符。在構造函數中,該標識值可以是整數或帶有 fileno() 方法的對象。kevent 在內部存儲整數。

kevent.filter?

內核篩選器的名稱(chēng)。

常量

含意

KQ_FILTER_READ

獲取描述符,并在有數據可讀時(shí)返回

KQ_FILTER_WRITE

獲取描述符,并在有數據可寫(xiě)時(shí)返回

KQ_FILTER_AIO

AIO 請求

KQ_FILTER_VNODE

當在 fflag 中監視的一個(gè)或多個(gè)請求事件發(fā)生時(shí)返回

KQ_FILTER_PROC

監視進(jìn)程ID上的事件

KQ_FILTER_NETDEV

Watch for events on a network device [not available on macOS]

KQ_FILTER_SIGNAL

每當監視的信號傳遞到進(jìn)程時(shí)返回

KQ_FILTER_TIMER

建立一個(gè)任意的計時(shí)器

kevent.flags?

篩選器操作。

常量

含意

KQ_EV_ADD

添加或修改事件

KQ_EV_DELETE

從隊列中刪除事件

KQ_EV_ENABLE

Permitscontrol() 返回事件

KQ_EV_DISABLE

禁用事件

KQ_EV_ONESHOT

在第一次發(fā)生后刪除事件

KQ_EV_CLEAR

檢索事件后重置狀態(tài)

KQ_EV_SYSFLAGS

內部事件

KQ_EV_FLAG1

內部事件

KQ_EV_EOF

篩選特定EOF條件

KQ_EV_ERROR

請參閱返回值

kevent.fflags?

篩選特定標志。

KQ_FILTER_READKQ_FILTER_WRITE 篩選標志:

常量

含意

KQ_NOTE_LOWAT

套接字緩沖區的低水線(xiàn)

KQ_FILTER_VNODE 篩選標志:

常量

含意

KQ_NOTE_DELETE

已調用 unlink()

KQ_NOTE_WRITE

發(fā)生寫(xiě)入

KQ_NOTE_EXTEND

文件已擴展

KQ_NOTE_ATTRIB

屬性已更改

KQ_NOTE_LINK

鏈接計數已更改

KQ_NOTE_RENAME

文件已重命名

KQ_NOTE_REVOKE

對文件的訪(fǎng)問(wèn)權限已被撤銷(xiāo)

KQ_FILTER_PROC filter flags:

常量

含意

KQ_NOTE_EXIT

進(jìn)程已退出

KQ_NOTE_FORK

該進(jìn)程調用了 fork()

KQ_NOTE_EXEC

進(jìn)程已執行新進(jìn)程

KQ_NOTE_PCTRLMASK

內部篩選器標志

KQ_NOTE_PDATAMASK

內部篩選器標志

KQ_NOTE_TRACK

fork() 執行進(jìn)程

KQ_NOTE_CHILD

NOTE_TRACK 的子進(jìn)程上返回

KQ_NOTE_TRACKERR

無(wú)法附加到子對象

KQ_FILTER_NETDEV filter flags (not available on macOS):

常量

含意

KQ_NOTE_LINKUP

鏈接已建立

KQ_NOTE_LINKDOWN

鏈接已斷開(kāi)

KQ_NOTE_LINKINV

鏈接狀態(tài)無(wú)效

kevent.data?

篩選特定數據。

kevent.udata?

用戶(hù)自定義值。