`selectors` — 고수준 I/O 멀티플렉싱

selectors — 고수준 I/O 멀티플렉싱

버전 3.4에서 추가됨.

selectors 모듈은 select 모듈의 프리미티브 위에 구축된, 고수준이고 효율적인 I/O 멀티플렉싱을 허용해요. OS 수준 프리미티브를 정밀하게 제어하고 싶지 않다면 이 모듈을 대신 쓰는 걸 권장해요.

이 모듈은 BaseSelector 추상 기본 클래스를 정의하고, 여러 개의 구체적 구현(KqueueSelector, EpollSelector 등)도 함께 정의해요. 이것들로 여러 파일 객체에 대한 I/O 준비 알림을 기다릴 수 있어요. 여기서 "파일 객체"는 fileno() 메서드를 가진 모든 객체 또는 원시 파일 디스크립터를 말해요.

DefaultSelector는 현재 플랫폼에서 사용 가능한 가장 효율적인 구현의 별칭이에요. 대부분의 사용자에게 기본 선택이 돼야 해요.

참고

지원되는 파일 객체의 타입은 플랫폼에 따라 달라요. Windows에서는 소켓은 지원하지만 파이프는 지원하지 않고, Unix에서는 둘 다 지원해요(파이프나 특수 파일 장치 같은 다른 타입도 지원될 수 있어요).

가용성: WASI 아님. 이 모듈은 WebAssembly에서 동작하지 않거나 사용할 수 없어요.

출처: Python 표준 라이브러리

본문

클래스 (Classes)

클래스 계층 구조:

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

여기서 events는 주어진 파일 객체에서 어떤 I/O 이벤트를 기다려야 하는지 나타내는 비트 마스크예요. 모듈의 아래 상수들을 조합할 수 있어요.

Constant Meaning
selectors.EVENT_READ 읽기 가능
selectors.EVENT_WRITE 쓰기 가능

class selectors.SelectorKey

SelectorKey는 파일 객체를 그 기본 파일 디스크립터, 선택된 이벤트 마스크, 첨부된 데이터와 연관시키는 데 쓰는 namedtuple이에요. 여러 BaseSelector 메서드가 반환해요.

  • fileobj: 등록된 파일 객체.
  • fd: 기본 파일 디스크립터.
  • events: 이 파일 객체에서 기다려야 하는 이벤트.
  • data: 이 파일 객체와 연관된 선택적 불투명 데이터. 예를 들어 클라이언트별 세션 ID를 저장하는 데 쓸 수 있어요.

class selectors.BaseSelector

BaseSelector는 여러 파일 객체에서 I/O 이벤트 준비를 기다리는 데 써요. 파일 스트림 등록, 등록 해제, 그리고 선택적 타임아웃으로 그 스트림에서 I/O 이벤트를 기다리는 메서드를 지원해요. 추상 기본 클래스라 인스턴스화할 수 없어요. DefaultSelector를 쓰거나, 특정 구현을 쓰고 싶고 플랫폼이 지원한다면 SelectSelector, KqueueSelector 등을 쓰세요. BaseSelector와 그 구체적 구현은 컨텍스트 관리자 프로토콜을 지원해요.

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

선택을 위해 파일 객체를 등록해 I/O 이벤트를 모니터링해요. fileobj는 모니터링할 파일 객체로, 정수 파일 디스크립터이거나 fileno() 메서드를 가진 객체일 수 있어요. events는 모니터링할 이벤트의 비트 마스크예요. data는 불투명 객체예요.

SelectorKey 인스턴스를 반환하거나, 잘못된 이벤트 마스크나 파일 디스크립터면 ValueError, 파일 객체가 이미 등록돼 있으면 KeyError를 발생시켜요.

abstractmethod unregister(*fileobj*)

파일 객체를 선택에서 등록 해제해 모니터링에서 제거해요. 파일 객체는 닫기 전에 등록 해제해야 해요. fileobj는 이전에 등록된 파일 객체여야 해요. 연관된 SelectorKey 인스턴스를 반환하거나, fileobj가 등록되지 않았으면 KeyError, fileobj가 잘못됐으면(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) 튜플 목록을 반환해요. key는 준비된 파일 객체에 대응하는 SelectorKey 인스턴스이고, events는 이 파일 객체에서 준비된 이벤트의 비트 마스크예요.

참고

현재 프로세스가 신호를 받으면 어떤 파일 객체도 준비되지 않았거나 타임아웃이 경과하지 않았어도 이 메서드가 반환할 수 있어요. 이 경우 빈 목록을 반환해요. 버전 3.5 변경: 신호 핸들러가 예외를 발생시키지 않았다면(PEP 475 참고), 타임아웃 전에 빈 이벤트 목록을 반환하는 대신 다시 계산된 타임아웃으로 셀렉터가 재시도됨.

close()

셀렉터를 닫아요. 기본 리소스가 해제되도록 반드시 호출해야 해요. 닫힌 후에는 셀렉터를 사용하면 안 돼요.

get_key(*fileobj*)

등록된 파일 객체와 연관된 키를 반환해요. 이 파일 객체와 연관된 SelectorKey 인스턴스를 반환하거나, 등록되지 않았으면 KeyError를 발생시켜요.

abstractmethod get_map()

파일 객체를 셀렉터 키에 매핑한 것을 반환해요. 등록된 파일 객체를 그 연관 SelectorKey 인스턴스에 매핑하는 Mapping 인스턴스를 반환해요.

class selectors.DefaultSelector

현재 플랫폼에서 사용 가능한 가장 효율적인 구현을 쓰는 기본 셀렉터 클래스예요. 대부분의 사용자에게 기본 선택이 돼야 해요.

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() 객체가 쓰는 파일 디스크립터를 반환해요.

예시 (Examples)

다음은 간단한 에코 서버 구현이에요.

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)

더 알아보기

  • select 모듈: 저수준 I/O 멀티플렉싱 모듈.