정책
****

An event loop policy is a global object used to get and set the
current event loop, as well as create new event loops. The default
policy can be replaced with built-in alternatives to use different
event loop implementations, or substituted by a custom policy that can
override these behaviors.

The policy object gets and sets a separate event loop per *context*.
This is per-thread by default, though custom policies could define
*context* differently.

Custom event loop policies can control the behavior of
"get_event_loop()", "set_event_loop()", and "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"
   가 사용됩니다.

   참고:

     In Python versions 3.10.9, 3.11.1 and 3.12 the "get_event_loop()"
     method of the default asyncio policy emits a "DeprecationWarning"
     if there is no running event loop and no current loop is set. In
     some future Python release this will become an error.

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 이벤트 루프가 실행되는 경우에도 신
   뢰성 있게 작동합니다.

   There is no noticeable overhead when handling a big number of
   children (*O*(1) each time a child terminates), but starting a
   thread per process requires extra memory.

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

   버전 3.8에 추가.

class asyncio.MultiLoopChildWatcher

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

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

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

   The solution is safe but it has a significant overhead when
   handling a big number of processes (*O*(*n*) each time a "SIGCHLD"
   is received).

   버전 3.8에 추가.

class asyncio.SafeChildWatcher

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

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

   This solution is as safe as "MultiLoopChildWatcher" and has the
   same *O*(*n*) complexity but requires a running event loop in the
   main thread to work.

class asyncio.FastChildWatcher

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

   There is no noticeable overhead when handling a big number of
   children (*O*(1) each time a child terminates).

   이 해법은 "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())
