정책
****

이벤트 루프 정책은 이벤트 루프의 관리를 제어하는 프로세스별 전역 객체
입니다. 각 이벤트 루프는 기본 정책이 있는데, 정책 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())
