selectors --- 高級 I/O 復(fù)用庫?

3.4 新版功能.

源碼: Lib/selectors.py


概述?

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

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

DefaultSelector 是一個指向當(dāng)前平臺上可用的最高效實現(xiàn)的別名:這應(yīng)為大多數(shù)用戶的默認(rèn)選擇。

備注

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

參見

select

低層級的 I/O 多路復(fù)用模塊。

?

類的層次結(jié)構(gòu):

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

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

常量

含意

EVENT_READ

可讀

EVENT_WRITE

可寫

class selectors.SelectorKey?

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

fileobj?

已注冊的文件對象。

fd?

下層的文件描述符。

events?

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

data?

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

class selectors.BaseSelector?

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

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

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

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

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

abstractmethod unregister(fileobj)?

注銷對一個文件對象的選擇,移除對它的監(jiān)視。 在文件對象被關(guān)閉之前應(yīng)當(dāng)先將其注銷。

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

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

modify(fileobj, events, data=None)?

更改已注冊文件對象所監(jiān)視的事件或所附帶的數(shù)據(jù)。

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

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

abstractmethod select(timeout=None)?

等待直到有已注冊的文件對象就緒,或是超過時限。

如果 timeout > 0,這指定以秒數(shù)表示的最大等待時間。 如果 timeout <= 0,調(diào)用將不會阻塞,并將報告當(dāng)前就緒的文件對象。 如果 timeoutNone,調(diào)用將阻塞直到某個被監(jiān)視的文件對象就緒。

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

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

備注

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

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

close()?

關(guān)閉選擇器。

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

get_key(fileobj)?

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

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

abstractmethod get_map()?

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

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

class selectors.DefaultSelector?

默認(rèn)的選擇器類,使用當(dāng)前平臺上可用的最高效實現(xiàn)。 這應(yīng)為大多數(shù)用戶的默認(rèn)選擇。

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

例子?

下面是一個簡單的回顯服務(wù)器實現(xiàn):

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)