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


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

備注

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

該模塊定義以下內(nèi)容:

exception select.error?

一個被棄用的 OSError 的別名。

在 3.3 版更改: 根據(jù) PEP 3151,這個類是 OSError 的別名。

select.devpoll()?

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

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

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

3.3 新版功能.

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

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

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

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

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

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

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

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

在 3.3 版更改: 增加了 flags 參數(shù)。

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

3.4 版后已移除: flags 參數(shù)?,F(xiàn)在默認(rèn)采用 select.EPOLL_CLOEXEC 標(biāo)志。使用 os.set_inheritable() 來讓文件描述符可繼承。

select.poll()?

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

select.kqueue()?

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

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

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

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

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

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

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

  • rlist:等待,直到可以開始讀取

  • wlist:等待,直到可以開始寫入

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

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

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

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

備注

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

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

select.PIPE_BUF?

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

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

可用性: Unix

3.2 新版功能.

/dev/poll 輪詢對象?

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

/dev/poll 的行為與標(biāo)準(zhǔn) poll() 對象十分類似。

devpoll.close()?

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

3.4 新版功能.

devpoll.closed?

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

3.4 新版功能.

devpoll.fileno()?

返回輪詢對象的文件描述符對應(yīng)的數(shù)字。

3.4 新版功能.

devpoll.register(fd[, eventmask])?

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

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

警告

注冊已注冊過的文件描述符不會報錯,但是結(jié)果是不確定的。正確的操作是先注銷或直接修改它。與 poll() 相比,這是一個重要的區(qū)別。

devpoll.modify(fd[, eventmask])?

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

devpoll.unregister(fd)?

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

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

devpoll.poll([timeout])?

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

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

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

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

eventmask

常量

含意

EPOLLIN

可讀

EPOLLOUT

可寫

EPOLLPRI

緊急數(shù)據(jù)讀取

EPOLLERR

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

EPOLLHUP

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

EPOLLET

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

EPOLLONESHOT

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

EPOLLEXCLUSIVE

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

EPOLLRDHUP

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

EPOLLRDNORM

等同于 EPOLLIN

EPOLLRDBAND

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

EPOLLWRNORM

等同于 EPOLLOUT

EPOLLWRBAND

可以寫入優(yōu)先級數(shù)據(jù)。

EPOLLMSG

忽略

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

epoll.close()?

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

epoll.closed?

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

epoll.fileno()?

返回文件描述符對應(yīng)的數(shù)字,該描述符用于控制 epoll 對象。

epoll.fromfd(fd)?

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

epoll.register(fd[, eventmask])?

在 epoll 對象中注冊一個文件描述符。

epoll.modify(fd, eventmask)?

修改一個已注冊的文件描述符。

epoll.unregister(fd)?

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

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

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

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

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

Poll 對象?

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

poll.register(fd[, eventmask])?

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

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

常量

含意

POLLIN

有要讀取的數(shù)據(jù)

POLLPRI

有緊急數(shù)據(jù)需要讀取

POLLOUT

準(zhǔn)備輸出:寫不會阻塞

POLLERR

某種錯誤條件

POLLHUP

掛起

POLLRDHUP

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

POLLNVAL

無效的請求:描述符未打開

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

poll.modify(fd, eventmask)?

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

poll.unregister(fd)?

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

嘗試刪除從未注冊過的文件描述符會拋出 KeyError 異常。

poll.poll([timeout])?

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

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

Kqueue 對象?

kqueue.close()?

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

kqueue.closed?

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

kqueue.fileno()?

返回文件描述符對應(yīng)的數(shù)字,該描述符用于控制 epoll 對象。

kqueue.fromfd(fd)?

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

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

Kevent 的低級接口

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

  • max_events 必須是 0 或一個正整數(shù)。

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

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

Kevent 對象?

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

kevent.ident?

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

kevent.filter?

內(nèi)核篩選器的名稱。

常量

含意

KQ_FILTER_READ

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

KQ_FILTER_WRITE

獲取描述符,并在有數(shù)據(jù)可寫時返回

KQ_FILTER_AIO

AIO 請求

KQ_FILTER_VNODE

當(dāng)在 fflag 中監(jiān)視的一個或多個請求事件發(fā)生時返回

KQ_FILTER_PROC

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

KQ_FILTER_NETDEV

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

KQ_FILTER_SIGNAL

每當(dāng)監(jiān)視的信號傳遞到進(jìn)程時返回

KQ_FILTER_TIMER

建立一個任意的計時器

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

內(nèi)部事件

KQ_EV_FLAG1

內(nèi)部事件

KQ_EV_EOF

篩選特定EOF條件

KQ_EV_ERROR

請參閱返回值

kevent.fflags?

篩選特定標(biāo)志。

KQ_FILTER_READKQ_FILTER_WRITE 篩選標(biāo)志:

常量

含意

KQ_NOTE_LOWAT

套接字緩沖區(qū)的低水線

KQ_FILTER_VNODE 篩選標(biāo)志:

常量

含意

KQ_NOTE_DELETE

已調(diào)用 unlink()

KQ_NOTE_WRITE

發(fā)生寫入

KQ_NOTE_EXTEND

文件已擴(kuò)展

KQ_NOTE_ATTRIB

屬性已更改

KQ_NOTE_LINK

鏈接計數(shù)已更改

KQ_NOTE_RENAME

文件已重命名

KQ_NOTE_REVOKE

對文件的訪問權(quán)限已被撤銷

KQ_FILTER_PROC filter flags:

常量

含意

KQ_NOTE_EXIT

進(jìn)程已退出

KQ_NOTE_FORK

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

KQ_NOTE_EXEC

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

KQ_NOTE_PCTRLMASK

內(nèi)部篩選器標(biāo)志

KQ_NOTE_PDATAMASK

內(nèi)部篩選器標(biāo)志

KQ_NOTE_TRACK

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

KQ_NOTE_CHILD

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

KQ_NOTE_TRACKERR

無法附加到子對象

KQ_FILTER_NETDEV filter flags (not available on macOS):

常量

含意

KQ_NOTE_LINKUP

鏈接已建立

KQ_NOTE_LINKDOWN

鏈接已斷開

KQ_NOTE_LINKINV

鏈接狀態(tài)無效

kevent.data?

篩選特定數(shù)據(jù)。

kevent.udata?

用戶自定義值。