18.4. selectors --- 高水準の I/O 多重化

バージョン 3.4 で追加.

ソースコード: Lib/selectors.py


18.4.1. はじめに

このモジュールにより、select モジュールプリミティブに基づく高水準かつ効率的な I/O の多重化が行えます。OS 水準のプリミティブを使用した正確な制御を求めない限り、このモジュールの使用が推奨されます。

このモジュールは BaseSelector 抽象基底クラスと、いくつかの具象実装 (KqueueSelector, EpollSelector...) を定義しており、これらは複数のファイルオブジェクトの I/O の準備状況の通知の待機に使用できます。以下では、 "ファイルオブジェクト" は、fileno() メソッドを持つあらゆるオブジェクトか、あるいは Raw ファイル記述子を意味します。ファイルオブジェクト を参照してください。

DefaultSelector は、現在のプラットフォームで利用できる、もっとも効率的な実装の別名になります: これはほとんどのユーザーにとってのデフォルトの選択になるはずです。

注釈

プラットフォームごとにサポートされているファイルオブジェクトのタイプは異なります: Windows ではソケットはサポートされますが、パイプはされません。Unix では両方がサポートされます (その他の fifo やスペシャルファイルデバイスなどのタイプもサポートされます)。

参考

select
低水準の I/O 多重化モジュールです。

18.4.2. クラス

クラス階層:

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

以下では、events は与えられたファイルオブジェクトを待機すべき I/O イベントを示すビット単位のマスクになります。これには以下のモジュール定数の組み合わせを設定できます:

定数 意味
EVENT_READ 読み込み可能
EVENT_WRITE 書き込み可能
class selectors.SelectorKey

SelectorKey はそれの下層のファイルディスクリプタ、選択したイベントマスク、および付属データへのファイルオブジェクトの関連付けに使用される namedtuple です。いくつかの BaseSelector メソッドを返します。

fileobj

登録されたファイルオブジェクトです。

fd

下層のファイル記述子です。

events

このファイルオブジェクトで待機しなければならないイベントです。

data

このファイルオブジェクトに関連付けられたオプションの不透明型 (Opaque) データです。例えば、これはクライアントごとのセッション ID を格納するために使用できます。

class selectors.BaseSelector

BaseSelector は複数のファイルオブジェクトの I/O イベントの準備状況の待機に使用されます。これはファイルストリームを登録、登録解除、およびこれらのストリームでの I/O イベントを待機 (オプションでタイムアウト) するメソッドをサポートします。これは抽象基底クラスであるため、インスタンスを作成できません。使用する実装を明示的に指定したい、そしてプラットフォームがそれをサポートしている場合は、代わりに DefaultSelector を使用するか、SelectSelectorKqueueSelector などの一つを使用します。BaseSelector とその具象実装は コンテキストマネージャー プロトコルをサポートしています。

abstractmethod register(fileobj, events, data=None)

I/O イベントを監視するファイルオブジェクトをセレクションに登録します。

fileobj は監視するファイルオブジェクトです。これは整数のファイル記述子か、fileno() メソッドを持つオブジェクトのどちらかになります。events は監視するイベントのビット幅マスクになります。data は不透明型 (Opaque) オブジェクトです。

これは新しい SelectorKey インスタンスを返します。不正なイベントマスク化ファイル記述子のときは ValueError が、ファイルオブジェクトがすでに登録済みのときは KeyError が送出されます。

abstractmethod unregister(fileobj)

ファイルオブジェクトのセレクション登録を解除し、監視対象から外します。ファイルオブジェクトの登録解除はそのクローズより前に行われます。

fileobj は登録済みのファイルオブジェクトでなければなりません。

関連付けられた SelectorKey インスタンスを返します。fileobj が登録されていない場合 KeyError を送出します。fileobj が不正な場合 (例えば fileobjfileno() メソッドが無い場合や fileno() メソッドの戻り値が不正な場合) ValueError を送出します。

modify(fileobj, events, data=None)

登録されたファイルオブジェクトの監視されたイベントや付属データを変更します。

より効率的に実装できる点を除けば、 BaseSelector.unregister(fileobj)() に続けて BaseSelector.register(fileobj, events, data)() を行うのと等価です。

新たな SelectorKey インスタンスを返します。 イベントマスクやファイル記述子が不正な場合は ValueError を、ファイルオブジェクトが登録されていない場合は KeyError を送出します。

abstractmethod select(timeout=None)

登録されたいくつかのファイルオブジェクトが準備できたか、タイムアウトするまで待機します。

timeout > 0 の場合、最大待機時間を秒で指定します。 timeout <= 0 の場合、この関数の呼び出しはブロックせず、 現在準備できているファイルオブジェクトを報告します。 timeoutNone の場合、監視しているファイルオブジェクトの一つが準備できるまでブロックします。

この関数は (key, events) タプルのリストを返します。準備できたファイルオブジェクトにつき1タプルです。

key は準備状態のファイルオブジェクトに対応する SelectorKey インスタンスです。 events はそのファイルオブジェクトで準備が完了したイベントのビットマスクです。

注釈

このメソッドは、現在のプロセスで信号を受信した場合、どのファイルオブジェクトも準備完了にならないうちに、またはタイムアウトが経過する前に返ることがあります。その場合、空のリストが返されます。

バージョン 3.5 で変更: このセレクタは、シグナルによって中断された時に、シグナルハンドラが例外を起こさなかった場合、空のイベントリストを返すのではなく、再計算されたタイムアウトによってリトライするようになりました (この論拠については PEP 475 を参照してください)。

close()

セレクタを閉じます。

下層のリソースがすべて解放されたことを確かめるために呼ばれなければなりません。一旦閉じられたセレクタは使ってはいけません。

get_key(fileobj)

登録されたファイルオブジェクトに関連付けられたキーを返します。

そのファイルオブジェクトに関連付けられた SelectorKey インスタンスを返します。そのファイルオブジェクトが登録されていない場合 KeyError を送出します。

abstractmethod get_map()

ファイルオブジェクトからセレクタキーへのマッピングを返します。

これは、登録済みのファイルオブジェクトを、それらに関連づけられた SelectorKey インスタンスにマッピングする Mapping のインスタンスを返します。

class selectors.DefaultSelector

デフォルトの selector クラスで、現在のプラットフォームで利用できる最も効率的な実装を使用しています。大半のユーザはこれをデフォルトにすべきです。

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() オブジェクトが使用しているファイル記述子を返します。

18.4.3. 使用例

簡単なエコーサーバの実装です:

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)