정책

이벤트 루프 정책은 이벤트 루프의 관리를 제어하는 프로세스별 전역 객체입니다. 각 이벤트 루프는 기본 정책이 있는데, 정책 API를 사용하여 변경하고 사용자 정의할 수 있습니다.

정책은 컨텍스트의 개념을 정의하고 컨텍스트마다 별도의 이벤트 루프를 관리합니다. 기본 정책은 컨텍스트를 현재 스레드로 정의합니다.

사용자 정의 이벤트 루프 정책을 사용하여, get_event_loop(), set_event_loop()new_event_loop() 함수의 동작을 사용자 정의할 수 있습니다.

정책 객체는 AbstractEventLoopPolicy 추상 베이스 클래스에 정의된 API를 구현해야 합니다.

정책을 얻고 설정하기

다음 함수는 현재 프로세스의 정책을 가져오고 설정하는 데 사용할 수 있습니다:

asyncio.get_event_loop_policy()

현재의 프로세스 전반의 정책을 돌려줍니다.

asyncio.set_event_loop_policy(policy)

현재 프로세스 전반의 정책을 policy로 설정합니다.

policyNone으로 설정하면, 기본 정책이 복원됩니다.

정책 객체

추상 이벤트 루프 정책 베이스 클래스는 다음과 같이 정의됩니다:

class asyncio.AbstractEventLoopPolicy

asyncio 정책의 추상 베이스 클래스.

get_event_loop()

현재 컨텍스트의 이벤트 루프를 가져옵니다.

AbstractEventLoop 인터페이스를 구현하는 이벤트 루프 객체를 반환합니다.

이 메서드는 절대 None을 반환해서는 안 됩니다.

버전 3.6에서 변경.

set_event_loop(loop)

현재 컨텍스트에 대한 이벤트 루프를 loop로 설정합니다.

new_event_loop()

새 이벤트 루프 객체를 만들고 반환합니다.

이 메서드는 절대 None을 반환해서는 안 됩니다.

get_child_watcher()

자식 프로세스 감시자 객체를 얻습니다.

AbstractChildWatcher 인터페이스를 구현하고 있는 감시자 객체를 돌려줍니다.

이 함수는 유닉스 전용입니다.

set_child_watcher(watcher)

현재의 자식 프로세스 감시자를 watcher로 설정합니다.

이 함수는 유닉스 전용입니다.

asyncio에는 다음과 같은 내장 정책이 제공됩니다:

class asyncio.DefaultEventLoopPolicy

기본 asyncio 정책. 유닉스에서는 SelectorEventLoop를, 윈도우에서는 ProactorEventLoop를 사용합니다.

수동으로 기본 정책을 설치할 필요는 없습니다. asyncio는 기본 정책을 자동으로 사용하도록 구성됩니다.

버전 3.8에서 변경: 윈도우에서, 이제 기본적으로 ProactorEventLoop가 사용됩니다.

class asyncio.WindowsSelectorEventLoopPolicy

SelectorEventLoop 이벤트 루프 구현을 사용하는 대안 이벤트 루프 정책.

가용성: 윈도우.

class asyncio.WindowsProactorEventLoopPolicy

ProactorEventLoop 이벤트 루프 구현을 사용하는 대안 이벤트 루프 정책.

가용성: 윈도우.

프로세스 감시자

프로세스 감시자는 이벤트 루프가 유닉스에서 자식 프로세스를 관찰하는 방법을 사용자 정의할 수 있도록 합니다. 특히, 이벤트 루프는 자식 프로세스가 언제 종료했는지 알 필요가 있습니다.

asyncio에서, 자식 프로세스는 create_subprocess_exec()loop.subprocess_exec() 함수로 만들어집니다.

asyncio는 자식 관찰자가 구현해야 하는 AbstractChildWatcher 추상 베이스 클래스를 정의하며, 네 가지 구현이 있습니다: ThreadedChildWatcher (기본적으로 사용하도록 구성됩니다), MultiLoopChildWatcher, SafeChildWatcherFastChildWatcher.

서브 프로세스와 스레드 절도 참조하십시오.

다음 두 함수를 사용하여 asyncio 이벤트 루프에서 사용되는 자식 프로세스 감시자 구현을 사용자 정의할 수 있습니다:

asyncio.get_child_watcher()

현재 정책에 대한 현재 자식 감시자를 반환합니다.

asyncio.set_child_watcher(watcher)

현재 정책에 대한 현재 자식 관찰자를 watcher로 설정합니다. watcherAbstractChildWatcher 베이스 클래스에 정의된 메서드를 구현해야 합니다.

참고

제삼자 이벤트 루프 구현은 사용자 정의 자식 관찰자를 지원하지 않을 수 있습니다. 이러한 이벤트 루프에서는, set_child_watcher() 사용은 금지되거나 효과가 없습니다.

class asyncio.AbstractChildWatcher
add_child_handler(pid, callback, *args)

새로운 자식 처리기를 등록합니다.

PID가 pid 인 프로세스가 종료할 때 callback(pid, returncode, *args)가 호출되도록 배치합니다. 같은 프로세스에 대해 다른 콜백을 지정하면 이전 처리기가 교체됩니다.

callback 콜러블은 스레드 안전해야 합니다.

remove_child_handler(pid)

PID가 pid 인 프로세스의 처리기를 제거합니다.

이 함수는 처리기가 성공적으로 제거되면 True를, 제거할 것이 없으면 False를 반환합니다.

attach_loop(loop)

감시자를 이벤트 루프에 연결합니다.

감시자가 이전에 이벤트 루프에 연결되었으면, 새 루프에 연결하기 전에 먼저 제거됩니다.

참고: loop는 None 일 수 있습니다.

is_active()

감시자가 사용할 준비가 되면 True를 반환합니다.

활성화되지 않은 현재 자식 감시자를 사용하여 서브 프로세스를 스폰하면 RuntimeError가 발생합니다.

버전 3.8에 추가.

close()

감시자를 닫습니다.

이 메서드는 하부 자원을 정리하기 위해 호출해야 합니다.

class asyncio.ThreadedChildWatcher

이 구현은 모든 서브 프로세스 스폰에 대해 새로운 대기 스레드를 시작합니다.

메인 외의 OS 스레드에서 asyncio 이벤트 루프가 실행되는 경우에도 신뢰성 있게 작동합니다.

많은 수의 자식을 처리할 때 눈에 띄는 오버헤드가 없습니다만 (자식이 종료될 때마다 O(1)), 프로세스마다 하나의 스레드 상태를 유지하는 데 추가 메모리가 필요합니다.

기본적으로 이 감시자가 사용됩니다.

버전 3.8에 추가.

class asyncio.MultiLoopChildWatcher

이 구현은 인스턴스를 만들 때 SIGCHLD 시그널 처리기를 등록합니다. SIGCHLD 시그널용 사용자 지정 처리기를 설치하는 제삼자 코드가 손상될 수 있습니다.).

감시자는 SIGCHLD 시그널에 대해 명시적으로 모든 프로세스를 폴링하여, 프로세스를 스포닝하는 다른 코드를 방해하지 않습니다.

감시자가 일단 설치되면 다른 스레드에서 서브 프로세스를 실행하는 데 제한이 없습니다.

이 해법은 안전하지만 많은 수의 프로세스를 처리할 때 상당한 오버헤드가 있습니다 (SIGCHLD가 수신될 때마다 O(n)).

버전 3.8에 추가.

class asyncio.SafeChildWatcher

이 구현은 메인 스레드의 활성 이벤트 루프를 사용하여 SIGCHLD 시그널을 처리합니다. 메인 스레드에 실행 중인 이벤트 루프가 없으면 다른 스레드는 서브 프로세스를 스폰할 수 없습니다 (RuntimeError가 발생합니다).

감시자는 SIGCHLD 시그널에 대해 명시적으로 모든 프로세스를 폴링하여, 프로세스를 스포닝하는 다른 코드를 방해하지 않습니다.

이 해법은 MultiLoopChildWatcher만큼 안전하고 같은 O(N) 복잡성을 갖고 있지만, 작동하려면 메인 스레드에서 실행 중인 이벤트 루프가 필요합니다.

class asyncio.FastChildWatcher

이 구현은 os.waitpid(-1)를 직접 호출하여 종료된 모든 프로세스를 거둡니다. 프로세스를 스포닝하는 다른 코드를 망가뜨리고 그들의 종료를 기다릴 수 있습니다.

많은 수의 자식을 처리할 때 눈에 띄는 오버헤드가 없습니다 (자식이 종료될 때마다 O(1)).

이 해법은 SafeChildWatcher처럼 작동하려면 메인 스레드에서 실행 중인 이벤트 루프가 필요합니다.

사용자 정의 정책

새로운 이벤트 루프 정책을 구현하려면, DefaultEventLoopPolicy의 서브 클래스를 만들고 사용자 정의 동작이 필요한 메서드를 재정의하는 것이 좋습니다, 예를 들어:

class MyEventLoopPolicy(asyncio.DefaultEventLoopPolicy):

    def get_event_loop(self):
        """Get the event loop.

        This may be None or an instance of EventLoop.
        """
        loop = super().get_event_loop()
        # Do something with loop ...
        return loop

asyncio.set_event_loop_policy(MyEventLoopPolicy())