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)容:
- select.devpoll()?
(僅支持 Solaris 及其衍生版本)返回一個
/dev/poll
輪詢對象,請參閱下方 /dev/poll 輪詢對象 獲取 devpoll 對象所支持的方法。devpoll()
對象與實例化時允許的文件描述符數(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)棄用且完全被忽略。但是,如果提供該值,則它必須是
0
或select.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()
方法(該方法要確實返回一個文件描述符,而不能只是一個隨機(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)實現(xiàn)了fileno()
,因此它們也可以用作參數(shù)。eventmask 是可選的位掩碼,用于指定要檢查的事件類型。這些常量與
poll()
對象所用的相同。本參數(shù)的默認(rèn)值是常量POLLIN
、POLLPRI
和POLLOUT
的組合。警告
注冊已注冊過的文件描述符不會報錯,但是結(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.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)實現(xiàn)了fileno()
,因此它們也可以用作參數(shù)。eventmask 是可選的位掩碼,用于指定要檢查的事件類型,它可以是常量
POLLIN
、POLLPRI
和POLLOUT
的組合,如下表所述。如果未指定本參數(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_READ
和KQ_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?
用戶自定義值。