# 정책

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

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

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

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

## 정책을 얻고 설정하기

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

`asyncio.``get_event_loop_policy`()

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

`asyncio.``set_event_loop_policy`(policy)

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

  policy를 `None`으로 설정하면, 기본 정책이 복원됩니다.

## 정책 객체

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

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`, `SafeChildWatcher` 및 `FastChildWatcher`.

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

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

`asyncio.``get_child_watcher`()

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

`asyncio.``set_child_watcher`(watcher)

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

참고

제삼자 이벤트 루프 구현은 사용자 정의 자식 관찰자를 지원하지 않을 수 있습니다. 이러한 이벤트 루프에서는, `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`처럼 작동하려면 메인 스레드에서 실행 중인 이벤트 루프가 필요합니다.

class `asyncio.``PidfdChildWatcher`

  이 구현은 프로세스 파일 기술자(pidfd)를 폴링하여 자식 프로세스 종료를 어웨이트 합니다. 어떤 면에서, `PidfdChildWatcher`는 “골디락스(Goldilocks)” 자식 감시자 구현입니다. 시그널이나 스레드가 필요하지 않고, 이벤트 루프 외부에서 시작된 프로세스를 방해하지 않으며, 이벤트 루프에 의해 시작된 서브 프로세스 수에 선형으로 확장됩니다. 가장 큰 단점은 pidfd가 리눅스에만 해당하며 최근 (5.3+) 커널에서만 작동한다는 것입니다.

  버전 3.9에 추가.

## 사용자 정의 정책

새로운 이벤트 루프 정책을 구현하려면, `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())