`select` — I/O 완료 대기하기
select — I/O 완료 대기하기
select 모듈은 운영체제에서 제공하는 select() 와 poll() 함수에 접근할 수 있게 해 줘요. Solaris 계열에서는 devpoll(), Linux 2.5+에서는 epoll(), 대부분의 BSD에서는 kqueue()를 쓸 수 있어요. Windows에서는 소켓에만 동작하고, 다른 운영체제에서는 다른 파일 종류(특히 Unix에서는 파이프)에도 동작해요. 다만 일반 파일에 대해서는 "마지막으로 읽은 이후 파일이 자라났는지"를 판별하는 용도로는 쓸 수 없어요.
출처: Python 표준 라이브러리
본문
참고:
selectors모듈은select모듈의 원시 연산 위에 구축된 고수준이고 효율적인 I/O 멀티플렉싱을 제공해요. OS 수준 원시 연산을 세밀하게 제어하고 싶지 않다면selectors모듈을 사용하는 걸 권장해요.
가용성(availability): WASI가 아님. 이 모듈은 WebAssembly 플랫폼에서는 동작하지 않거나 사용할 수 없어요.
이 모듈은 다음 항목들을 정의해요.
예외
select.error
OSError 의 더 이상 쓰이지 않는(비권장) 별칭이에요.
3.3 버전 변경: PEP 3151 에 따라 이 클래스가
OSError의 별칭이 되었어요.
함수
select.devpoll()
/dev/poll 폴링 객체를 반환해요. devpoll 객체가 지원하는 메서드는 아래 /dev/poll polling objects 절을 참고하세요.
devpoll() 객체는 인스턴스를 만들 당시 허용된 파일 디스크립터 수에 연결돼 있어요. 프로그램이 이 값을 줄이면 devpoll() 은 실패하고, 늘리면 devpoll() 이 활성 파일 디스크립터의 불완전한 목록을 반환할 수 있어요.
새로 만든 파일 디스크립터는 상속 불가(non-inheritable)예요.
3.3 버전에서 추가.
3.4 버전 변경: 이제 새 파일 디스크립터가 non-inheritable 해졌어요.
가용성: Solaris.
select.epoll(*sizehint=-1, *flags=0)
가장자리(Edge) 또는 수준(Level) 트리거 방식의 I/O 이벤트 인터페이스로 쓸 수 있는 가자리 폴링 객체를 반환해요.
sizehint는 등록될 것으로 예상되는 이벤트 수를 epoll에 알려줘요. 양수여야 하고, 기본값을 쓰려면-1이에요.epoll_create1()을 쓸 수 없는 오래된 시스템에서만 쓰이고, 그 외에는 효과가 없어요(값은 여전히 검사되지만요).flags는 비권장되고 완전히 무시돼요. 다만 제공할 때는 값이0또는select.EPOLL_CLOEXEC여야 하고, 그렇지 않으면OSError가 발생해요.
epoll 객체가 지원하는 메서드는 아래 Edge and level trigger polling (epoll) objects 절을 참고하세요.
epoll 객체는 컨텍스트 관리 프로토콜(context management protocol)을 지원해요. with 문에 쓰면 블록이 끝날 때 새 파일 디스크립터가 자동으로 닫혀요.
새 파일 디스크립터는 non-inheritable이에요.
3.3 버전 변경:
flags매개변수가 추가됐어요.3.4 버전 변경:
with문 지원이 추가됐고, 새 파일 디스크립터가 non-inheritable 해졌어요.3.4 이후 비권장:
flags매개변수. 이제 기본으로select.EPOLL_CLOEXEC가 쓰여요. 파일 디스크립터를 상속 가능하게 하려면os.set_inheritable()을 쓰세요.가용성: Linux >= 2.5.44.
select.poll()
폴링 객체를 반환해요. 파일 디스크립터를 등록·해제하고 I/O 이벤트를 폴링할 수 있어요. 폴링 객체가 지원하는 메서드는 아래 Polling objects 절을 참고하세요.
가용성: Unix.
select.kqueue()
커널 큐(kernel queue) 객체를 반환해요. kqueue 객체가 지원하는 메서드는 아래 Kqueue objects 절을 참고하세요.
새 파일 디스크립터는 non-inheritable이에요.
3.4 버전 변경: 이제 새 파일 디스크립터가 non-inheritable 해졌어요.
가용성: BSD, macOS.
select.kevent(*ident, *filter=KQ_FILTER_READ, *flags=KQ_EV_ADD, *fflags=0, *data=0, *udata=0)
커널 이벤트 객체를 반환해요. kevent 객체가 지원하는 메서드는 아래 Kevent objects 절을 참고하세요.
가용성: BSD, macOS.
select.select(*rlist, *wlist, *xlist, *timeout=None)
Unix select() 시스템 호출에 대한 직관적인 인터페이스예요. 처음 세 인자는 '대기 가능한 객체(waitable objects)'의 이터러블이에요. 즉 파일 디스크립터를 나타내는 정수이거나, 그런 정수를 반환하는 매개변수 없는 fileno() 메서드를 가진 객체예요.
rlist: 읽을 준비가 될 때까지 대기wlist: 쓸 준비가 될 때까지 대기xlist: "예외 조건(exceptional condition)"을 대기 (어떤 조건을 그렇게 보는지는 시스템 매뉴얼 참고)
빈 이터러블은 허용되지만, 세 개 모두 빈 이터러블을 받는지는 플랫폼에 따라 달라요(Unix에서는 동작하는 것으로 알려져 있지만 Windows에서는 아님). 선택적인 timeout 인자는 초 단위 부동소수점 숫자로 제한 시간을 지정해요. timeout을 생략하거나 None으로 주면 함수는 파일 디스크립터가 최소 하나 준비될 때까지 블로킹해요. 타임아웃 값이 0이면 폴링(poll)을 의미하고 절대 블로킹하지 않아요.
반환 값은 준비된 객체들의 리스트 세 개의 튜플로, 각각 처음 세 인자의 부분집합이에요. 타임아웃이 됐는데도 준비된 파일 디스크립터가 없으면 빈 리스트 세 개를 반환해요.
이터러블에 허용되는 객체 종류에는 Python 파일 객체(예: sys.stdin 이나 open() 또는 os.popen()이 반환한 객체), socket.socket()이 반환한 소켓 객체가 있어요. 적절한 fileno() 메서드(진짜 파일 디스크립터를 반환하는, 단순한 임의 정수가 아닌)만 있으면 wrapper 클래스를 직접 정의해도 돼요.
참고: Windows에서는 파일 객체는 허용되지 않고 소켓만 허용돼요. Windows에서 내부적으로
select()함수는 WinSock 라이브러리가 제공하는데, WinSock에서 비롯되지 않은 파일 디스크립터는 다루지 않아요.
3.5 버전 변경: 이제 신호에 의해 중단되면
InterruptedError를 발생시키는 대신 다시 계산된 타임아웃으로 재시도돼요(신호 핸들러가 예외를 일으키는 경우 제외, 근거는 PEP 475 참고).
select.PIPE_BUF
파이프가 select(), poll() 또는 이 모듈의 다른 인터페이스로 쓰기 준비가 되었다고 보고됐을 때 블로킹 없이 파이프에 쓸 수 있는 최소 바이트 수예요. 소켓 같은 다른 종류의 파일류 객체에는 적용되지 않아요.
POSIX는 이 값이 최소 512라고 보장해요.
가용성: Unix.
3.2 버전에서 추가.
/dev/poll polling objects
Solaris와 그 파생 제품에는 /dev/poll이 있어요. select() 는 O(가장 높은 파일 디스크립터), poll() 은 O(파일 디스크립터 수)인 반면, /dev/poll 은 O(활성 파일 디스크립터)예요.
/dev/poll 의 동작은 표준 poll() 객체와 매우 비슷해요.
devpoll.close()
폴링 객체의 파일 디스크립터를 닫아요.
3.4 버전에서 추가.
devpoll.closed
폴링 객체가 닫혔으면 True.
3.4 버전에서 추가.
devpoll.fileno()
폴링 객체의 파일 디스크립터 번호를 반환해요.
3.4 버전에서 추가.
devpoll.register(*fd*[, *eventmask*])
파일 디스크립터를 폴링 객체에 등록해요. 이후 poll() 메서드 호출에서 그 파일 디스크립터에 보류 중인 I/O 이벤트가 있는지 확인하게 돼요. fd 는 정수이거나 정수를 반환하는 fileno() 메서드를 가진 객체일 수 있어요. 파일 객체는 fileno() 를 구현하므로 인자로 쓸 수 있어요.
eventmask 는 확인하고 싶은 이벤트 종류를 설명하는 선택적 비트마스크예요. 상수는 poll() 객체와 같아요. 기본값은 POLLIN, POLLPRI, POLLOUT 상수의 조합이에요.
경고: 이미 등록된 파일 디스크립터를 다시 등록하는 것은 오류가 아니지만 결과는 정의되지 않아요. 적절한 방법은 먼저 해제(unregister)하거나 수정(modify)하는 것이에요. 이것은
poll()과 비교했을 때 중요한 차이점이에요.
devpoll.modify(*fd*[, *eventmask*])
이 메서드는 unregister() 다음에 register() 를 수행해요. 명시적으로 두 번 하는 것보다 (약간) 더 효율적이에요.
devpoll.unregister(*fd*)
폴링 객체가 추적하는 파일 디스크립터를 제거해요. register() 메서드처럼 fd 는 정수이거나 정수를 반환하는 fileno() 메서드를 가진 객체일 수 있어요.
등록된 적 없는 파일 디스크립터를 제거하려는 시도는 안전하게 무시돼요.
devpoll.poll([*timeout*])
등록된 파일 디스크립터들의 집합을 폴링하고, 이벤트나 오류를 보고할 디스크립터에 대한 (fd, event) 2-튜플을 담은 (비어 있을 수도 있는) 리스트를 반환해요. fd 는 파일 디스크립터이고, event 는 그 디스크립터에 대해 보고된 이벤트들의 비트가 설정된 비트마스크예요. 입력 대기(POLLIN), 디스크립터에 쓸 수 있음(POLLOUT) 등을 나타내요. 빈 리스트는 호출이 타임아웃되어 이벤트를 보고할 파일 디스크립터가 없었음을 의미해요. timeout 이 주어지면 시스템이 이벤트를 기다릴 시간을 밀리초 단위로 지정해요. timeout 을 생략하거나, -1 이거나 None이면 호출은 이 poll 객체에 이벤트가 있을 때까지 블로킹해요.
3.5 버전 변경: 이제 신호에 의해 중단되면
InterruptedError대신 다시 계산된 타임아웃으로 재시도돼요(신호 핸들러가 예외를 일으키는 경우 제외, 근거는 PEP 475 참고).
Edge and level trigger polling (epoll) objects
eventmask 는 다음 상수들을 쓰는 비트 마스크예요.
| Constant | Meaning |
|---|---|
EPOLLIN |
읽을 수 있음(available for read). |
EPOLLOUT |
쓸 수 있음(available for write). |
EPOLLPRI |
긴급 데이터를 읽을 수 있음. |
EPOLLERR |
연결된 fd에서 오류 조건이 발생했음. |
EPOLLHUP |
연결된 fd에서 hang up이 발생했음. |
EPOLLET |
가장자리 트리거(Edge Trigger) 동작을 설정. 기본은 수준 트리거(Level Trigger) 동작. |
EPOLLONESHOT |
원샷(one-shot) 동작 설정. 이벤트 하나가 꺼내지면 fd가 내부적으로 비활성화됨. |
EPOLLEXCLUSIVE |
연결된 fd에 이벤트가 있을 때 하나의 epoll 객체만 깨움. 기본(이 플래그가 설정되지 않은 경우)은 fd에 폴링하는 모든 epoll 객체를 깨움. |
EPOLLRDHUP |
스트림 소켓 피어가 연결을 닫거나 연결의 쓰기 절반을 종료함. |
EPOLLRDNORM |
EPOLLIN 과 동등. |
EPOLLRDBAND |
우선순위 데이터 대역을 읽을 수 있음. |
EPOLLWRNORM |
EPOLLOUT 과 동등. |
EPOLLWRBAND |
우선순위 데이터를 쓸 수 있음. |
EPOLLMSG |
무시됨. |
EPOLLWAKEUP |
이벤트 대기 중 sleep 방지. |
3.6 버전에서 추가:
EPOLLEXCLUSIVE가 추가됐어요. Linux 커널 4.5 이상에서만 지원돼요.3.14 버전에서 추가:
EPOLLWAKEUP이 추가됐어요. Linux 커널 3.5 이상에서만 지원돼요.
epoll.close()
epoll 객체의 제어 파일 디스크립터를 닫아요.
epoll.closed
epoll 객체가 닫혔으면 True.
epoll.fileno()
제어 fd의 파일 디스크립터 번호를 반환해요.
epoll.fromfd(*fd*)
주어진 파일 디스크립터로부터 epoll 객체를 만들어요.
epoll.register(*fd*[, *eventmask*])
파일 디스크립터 fd 를 epoll 객체에 등록해요.
epoll.modify(*fd*, *eventmask*)
등록된 파일 디스크립터 fd 를 수정해요.
epoll.unregister(*fd*)
등록된 파일 디스크립터를 epoll 객체에서 제거해요.
3.9 버전 변경: 이 메서드는 더 이상
EBADF오류를 무시하지 않아요.
epoll.poll(*timeout=None, *maxevents=-1*)
이벤트를 기다려요. timeout은 초 단위(부동소수점)예요.
3.5 버전 변경: 이제 신호에 의해 중단되면
InterruptedError대신 다시 계산된 타임아웃으로 재시도돼요(신호 핸들러가 예외를 일으키는 경우 제외, 근거는 PEP 475 참고).
Polling objects
대부분의 Unix 시스템에서 지원되는 poll() 시스템 호출은 동시에 매우 많은 클라이언트를 서비스하는 네트워크 서버에 더 나은 확장성을 제공해요. poll() 은 관심 있는 파일 디스크립터만 나열하면 되지만 select() 는 비트맵을 만들고 관심 있는 fd에 비트를 켠 다음 나중에 전체 비트맵을 다시 선형적으로 스캔해야 하기 때문에 더 잘 확장돼요. select() 는 O(가장 높은 파일 디스크립터)이고 poll() 은 O(파일 디스크립터 수)예요.
poll.register(*fd*[, *eventmask*])
파일 디스크립터를 폴링 객체에 등록해요. 이후 poll() 메서드 호출에서 그 파일 디스크립터에 보류 중인 I/O 이벤트가 있는지 확인하게 돼요. fd 는 정수이거나 정수를 반환하는 fileno() 메서드를 가진 객체일 수 있어요. 파일 객체는 fileno() 를 구현하므로 인자로 쓸 수 있어요.
eventmask 는 확인하고 싶은 이벤트 종류를 설명하는 선택적 비트마스크로, 아래 표에 설명된 POLLIN, POLLPRI, POLLOUT 상수의 조합일 수 있어요. 지정하지 않으면 기본값으로 세 종류의 이벤트를 모두 확인해요.
| Constant | Meaning |
|---|---|
POLLIN |
읽을 데이터가 있음. |
POLLPRI |
긴급하게 읽을 데이터가 있음. |
POLLOUT |
출력 준비 완료: 쓰기가 블로킹되지 않음. |
POLLERR |
어떤 종류의 오류 조건. |
POLLHUP |
연결 끊김(hung up). |
POLLRDHUP |
스트림 소켓 피어가 연결을 닫거나 연결의 쓰기 절반을 종료함. |
POLLNVAL |
잘못된 요청: 디스크립터가 열려 있지 않음. |
이미 등록된 파일 디스크립터를 다시 등록하는 것은 오류가 아니며, 디스크립터를 정확히 한 번 등록한 것과 같은 효과를 가져요.
poll.modify(*fd*, *eventmask*)
이미 등록된 fd를 수정해요. register(fd, eventmask) 와 같은 효과를 가져요. 등록된 적 없는 파일 디스크립터를 수정하려 하면 errno ENOENT 를 가진 OSError 예외가 발생해요.
poll.unregister(*fd*)
폴링 객체가 추적하는 파일 디스크립터를 제거해요. register() 메서드처럼 fd 는 정수이거나 정수를 반환하는 fileno() 메서드를 가진 객체일 수 있어요.
등록된 적 없는 파일 디스크립터를 제거하려 하면 KeyError 예외가 발생해요.
poll.poll([*timeout*])
등록된 파일 디스크립터들의 집합을 폴링하고, 이벤트나 오류를 보고할 디스크립터에 대한 (fd, event) 2-튜플을 담은 (비어 있을 수도 있는) 리스트를 반환해요. fd 는 파일 디스크립터이고, event 는 그 디스크립터에 대해 보고된 이벤트들의 비트가 설정된 비트마스크예요(입력 대기 POLLIN, 디스크립터에 쓸 수 있음 POLLOUT 등). 빈 리스트는 호출이 타임아웃되어 이벤트를 보고할 파일 디스크립터가 없었음을 의미해요. timeout 이 주어지면 시스템이 이벤트를 기다릴 시간을 밀리초 단위로 지정해요. timeout 을 생략하거나 음수이거나 None이면 호출은 이 poll 객체에 이벤트가 있을 때까지 블로킹해요.
3.5 버전 변경: 이제 신호에 의해 중단되면
InterruptedError대신 다시 계산된 타임아웃으로 재시도돼요(신호 핸들러가 예외를 일으키는 경우 제외, 근거는 PEP 475 참고).
Kqueue objects
kqueue.close()
kqueue 객체의 제어 파일 디스크립터를 닫아요.
kqueue.closed
kqueue 객체가 닫혔으면 True.
kqueue.fileno()
제어 fd의 파일 디스크립터 번호를 반환해요.
kqueue.fromfd(*fd*)
주어진 파일 디스크립터로부터 kqueue 객체를 만들어요.
kqueue.control(*changelist*, *max_events*[, *timeout*]) → eventlist
kevent에 대한 저수준 인터페이스예요.
- changelist는 kevent 객체들의 이터러블 또는
None이어야 해요. - max_events는 0 또는 양의 정수여야 해요.
- timeout은 초 단위(부동소수점 가능)이고 기본은
None으로 영원히 기다려요.
3.5 버전 변경: 이제 신호에 의해 중단되면
InterruptedError대신 다시 계산된 타임아웃으로 재시도돼요(신호 핸들러가 예외를 일으키는 경우 제외, 근거는 PEP 475 참고).
Kevent objects
kevent.ident
이벤트를 식별하는 데 쓰는 값이에요. 해석은 필터에 따라 다르지만 보통 파일 디스크립터예요. 생성자에서 ident는 int이거나 fileno() 메서드를 가진 객체일 수 있어요. kevent는 내부적으로 정수를 저장해요.
kevent.filter
커널 필터의 이름이에요.
| Constant | Meaning |
|---|---|
KQ_FILTER_READ |
디스크립터를 받고 읽을 수 있는 데이터가 있을 때마다 반환. |
KQ_FILTER_WRITE |
디스크립터를 받고 쓸 수 있는 데이터가 있을 때마다 반환. |
KQ_FILTER_AIO |
AIO 요청. |
KQ_FILTER_VNODE |
fflag 에서 감시 중인 요청된 이벤트 중 하나 이상이 발생하면 반환. |
KQ_FILTER_PROC |
프로세스 ID에 대한 이벤트를 감시. |
KQ_FILTER_NETDEV |
네트워크 장치에 대한 이벤트를 감시(macOS에서는 사용 불가). |
KQ_FILTER_SIGNAL |
감시 중인 신호가 프로세스에 전달될 때마다 반환. |
KQ_FILTER_TIMER |
임의의 타이머를 설정. |
kevent.flags
필터 동작을 나타내요.
| Constant | Meaning |
|---|---|
KQ_EV_ADD |
이벤트를 추가하거나 수정. |
KQ_EV_DELETE |
큐에서 이벤트를 제거. |
KQ_EV_ENABLE |
control()이 이벤트를 반환하도록 허용. |
KQ_EV_DISABLE |
이벤트를 비활성화. |
KQ_EV_ONESHOT |
첫 발생 후 이벤트를 제거. |
KQ_EV_CLEAR |
이벤트가 검색된 후 상태를 리셋. |
KQ_EV_SYSFLAGS |
내부 이벤트. |
KQ_EV_FLAG1 |
내부 이벤트. |
KQ_EV_EOF |
필터별 EOF 조건. |
KQ_EV_ERROR |
반환 값을 참고. |
kevent.fflags
필터별 플래그예요.
KQ_FILTER_READ 및 KQ_FILTER_WRITE 필터 플래그:
| Constant | Meaning |
|---|---|
KQ_NOTE_LOWAT |
소켓 버퍼의 low water mark. |
KQ_FILTER_VNODE 필터 플래그:
| Constant | Meaning |
|---|---|
KQ_NOTE_DELETE |
unlink() 가 호출됨. |
KQ_NOTE_WRITE |
쓰기 발생. |
KQ_NOTE_EXTEND |
파일이 확장됨. |
KQ_NOTE_ATTRIB |
속성이 변경됨. |
KQ_NOTE_LINK |
링크 수가 변경됨. |
KQ_NOTE_RENAME |
파일이 이름 변경됨. |
KQ_NOTE_REVOKE |
파일 접근이 회수됨. |
KQ_FILTER_PROC 필터 플래그:
| Constant | Meaning |
|---|---|
KQ_NOTE_EXIT |
프로세스가 종료됨. |
KQ_NOTE_FORK |
프로세스가 fork() 를 호출함. |
KQ_NOTE_EXEC |
프로세스가 새 프로세스를 실행함. |
KQ_NOTE_PCTRLMASK |
내부 필터 플래그. |
KQ_NOTE_PDATAMASK |
내부 필터 플래그. |
KQ_NOTE_TRACK |
fork() 를 따라 프로세스를 추적. |
KQ_NOTE_CHILD |
NOTE_TRACK 에 대해 자식 프로세스에서 반환됨. |
KQ_NOTE_TRACKERR |
자식에 붙을 수 없음. |
KQ_FILTER_NETDEV 필터 플래그(macOS에서 사용 불가):
| Constant | Meaning |
|---|---|
KQ_NOTE_LINKUP |
링크가 올라감. |
KQ_NOTE_LINKDOWN |
링크가 내려감. |
KQ_NOTE_LINKINV |
링크 상태가 유효하지 않음. |
kevent.data
필터별 데이터예요.
kevent.udata
사용자 정의 값이에요.
더 알아보기
selectors—select위에 구축된 고수준 I/O 멀티플렉싱 모듈로, 일반적인 용도로는 이쪽을 권장해요.