selectors --- 高級 I/O 復用庫?

3.4 新版功能.

源碼: Lib/selectors.py


概述?

此模塊允許高層級且高效率的 I/O 復用,它建立在 select 模塊原型的基礎之上。 推薦用戶(hù)改用此模塊,除非他們希望對所使用的 OS 層級原型進(jìn)行精確控制。

它定義了一個(gè) BaseSelector 抽象基類(lèi),以及多個(gè)實(shí)際的實(shí)現 (KqueueSelector, EpollSelector...),它們可被用于在多個(gè)文件對象上等待 I/O 就緒通知。 在下文中,"文件對象" 是指任何具有 fileno() 方法的對象,或是一個(gè)原始文件描述符。 參見(jiàn) file object。

DefaultSelector 是一個(gè)指向當前平臺上可用的最高效實(shí)現的別名:這應為大多數用戶(hù)的默認選擇。

備注

受支持的文件對象類(lèi)型取決于具體平臺:在 Windows 上,支持套接字但不支持管道,而在 Unix 上兩者均受支持(某些其他類(lèi)型也可能受支持,例如 fifo 或特殊文件設備等)。

參見(jiàn)

select

低層級的 I/O 多路復用模塊。

類(lèi)?

類(lèi)的層次結構:

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

下文中,events 一個(gè)位掩碼,指明哪些 I/O 事件要在給定的文件對象上執行等待。 它可以是以下模塊級常量的組合:

常量

含意

EVENT_READ

可讀

EVENT_WRITE

可寫(xiě)

class selectors.SelectorKey?

SelectorKey 是一個(gè) namedtuple,用來(lái)將文件對象關(guān)聯(lián)到其下層的文件描述符、選定事件掩碼和附加數據等。 它會(huì )被某些 BaseSelector 方法返回。

fileobj?

已注冊的文件對象。

fd?

下層的文件描述符。

events?

必須在此文件對象上被等待的事件。

data?

可選的關(guān)聯(lián)到此文件對象的不透明數據:例如,這可被用來(lái)存儲各個(gè)客戶(hù)端的會(huì )話(huà) ID。

class selectors.BaseSelector?

一個(gè) BaseSelector,用來(lái)在多個(gè)文件對象上等待 I/O 事件就緒。 它支持文件流注冊、注銷(xiāo),以及在這些流上等待 I/O 事件的方法。 它是一個(gè)抽象基類(lèi),因此不能被實(shí)例化。 請改用 DefaultSelector,或者 SelectSelector, KqueueSelector 等。 如果你想要指明使用某個(gè)實(shí)現,并且你的平臺支持它的話(huà)。 BaseSelector 及其具體實(shí)現支持 context manager 協(xié)議。

abstractmethod register(fileobj, events, data=None)?

注冊一個(gè)用于選擇的文件對象,在其上監視 I/O 事件。

fileobj 是要監視的文件對象。 它可以是整數形式的文件描述符或者具有 fileno() 方法的對象。 events 是要監視的事件的位掩碼。 data 是一個(gè)不透明對象。

這將返回一個(gè)新的 SelectorKey 實(shí)例,或在出現無(wú)效事件掩碼或文件描述符時(shí)引發(fā) ValueError,或在文件對象已被注冊時(shí)引發(fā) KeyError。

abstractmethod unregister(fileobj)?

注銷(xiāo)對一個(gè)文件對象的選擇,移除對它的監視。 在文件對象被關(guān)閉之前應當先將其注銷(xiāo)。

fileobj 必須是之前已注冊的文件對象。

這將返回已關(guān)聯(lián)的 SelectorKey 實(shí)例,或者如果 fileobj 未注冊則會(huì )引發(fā) KeyError。 It will raise ValueError 如果 fileobj 無(wú)效(例如它沒(méi)有 fileno() 方法或其 fileno() 方法返回無(wú)效值)。

modify(fileobj, events, data=None)?

更改已注冊文件對象所監視的事件或所附帶的數據。

這等價(jià)于 BaseSelector.unregister(fileobj)()BaseSelector.register(fileobj, events, data)(),區別在于它可以被更高效地實(shí)現。

這將返回一個(gè)新的 SelectorKey 實(shí)例,或在出現無(wú)效事件掩碼或文件描述符時(shí)引發(fā) ValueError,或在文件對象未被注冊時(shí)引發(fā) KeyError。

abstractmethod select(timeout=None)?

等待直到有已注冊的文件對象就緒,或是超過(guò)時(shí)限。

如果 timeout > 0,這指定以秒數表示的最大等待時(shí)間。 如果 timeout <= 0,調用將不會(huì )阻塞,并將報告當前就緒的文件對象。 如果 timeoutNone,調用將阻塞直到某個(gè)被監視的文件對象就緒。

這將返回由 (key, events) 元組構成的列表,每項各表示一個(gè)就緒的文件對象。

key 是對應于就緒文件對象的 SelectorKey 實(shí)例。 events 是在此文件對象上等待的事件位掩碼。

備注

如果當前進(jìn)程收到一個(gè)信號,此方法可在任何文件對象就緒之前或超出時(shí)限時(shí)返回:在此情況下,將返回一個(gè)空列表。

在 3.5 版更改: 現在當被某個(gè)信號中斷時(shí),如果信號處理程序沒(méi)有引發(fā)異常,選擇器會(huì )用重新計算的超時(shí)值進(jìn)行重試(請查看 PEP 475 其理由),而不是在超時(shí)之前返回空的事件列表。

close()?

關(guān)閉選擇器。

必須調用這個(gè)方法以確保下層資源會(huì )被釋放。 選擇器被關(guān)閉后將不可再使用。

get_key(fileobj)?

返回關(guān)聯(lián)到某個(gè)已注冊文件對象的鍵。

此方法將返回關(guān)聯(lián)到文件對象的 SelectorKey 實(shí)例,或在文件對象未注冊時(shí)引發(fā) KeyError。

abstractmethod get_map()?

返回從文件對象到選擇器鍵的映射。

這將返回一個(gè)將已注冊文件對象映射到與其相關(guān)聯(lián)的 SelectorKey 實(shí)例的 Mapping 實(shí)例。

class selectors.DefaultSelector?

默認的選擇器類(lèi),使用當前平臺上可用的最高效實(shí)現。 這應為大多數用戶(hù)的默認選擇。

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() 對象所使用的文件描述符。

例子?

下面是一個(gè)簡(jiǎn)單的回顯服務(wù)器實(shí)現:

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)