>  기사  >  백엔드 개발  >  Python은 재시작된 비동기 IO를 지원합니다.

Python은 재시작된 비동기 IO를 지원합니다.

高洛峰
高洛峰원래의
2016-10-18 11:50:131148검색

요약


Python3.3부터 시작하는 Python3 비동기 I/O 제안입니다. PEP 3153에서 누락된 특정 제안을 연구합니다. 이 제안에는 플러그형 이벤트 루프 API, Twisted와 유사한 전송 및 프로토콜 추상화는 물론 (PEP 380)의 더 높은 수준의 수율 기반 스케줄러가 포함됩니다. 작업의 참조 구현인 해당 코드의 이름은 Tulip입니다(Tulip의 저장소에 대한 링크는 기사 끝 부분의 참조 섹션에 있습니다).

소개


이벤트 루프는 상호 운용성이 높은 곳에서 자주 사용됩니다. Twisted, Tornado 또는 ZeroMQ(Python 3.3 기반)와 같은 프레임워크의 경우 프레임워크의 필요에 따라 경량 래퍼 또는 프록시를 통해 기본 이벤트 루프 구현을 쉽게 적용하거나 자체 이벤트 루프 구현을 사용하여 기본값을 대체해야 합니다. 구현. (Twisted와 같은 일부 프레임워크에는 여러 이벤트 루프 구현이 있습니다. 이러한 구현에는 모두 통합된 인터페이스가 있으므로 문제가 되지 않습니다.)

두 가지 다른 이벤트 루프가 있을 수도 있습니다. 기본 이벤트 루프(각각 자체 어댑터 사용)를 공유하거나 프레임워크 중 하나의 이벤트 루프를 공유하여 구현됩니다. 후자의 경우 두 가지 다른 적응 수준이 존재할 수 있습니다(프레임워크 A의 이벤트 루프에서 표준 이벤트 루프 인터페이스로, 그리고 표준에서 프레임워크 B의 이벤트 루프로). 사용되는 이벤트 루프 구현은 기본 프로그램의 제어하에 있어야 합니다(이벤트 루프가 선택할 수 있는 기본 전략이 제공되지만).

따라서 두 가지 별도의 API가 정의됩니다.

현재 이벤트 루프 개체 가져오기 및 설정

이벤트 루프 개체 및 해당 최소 보장을 확인하는 인터페이스

이벤트 루프 구현은 추가 방법과 보장을 제공할 수 있습니다.

이벤트 루프 인터페이스는 출력에 의존하지 않고 대신 콜백, 추가 인터페이스(전송 프로토콜 및 프로토콜) 및 미래(?)의 조합을 사용합니다. 후자는 PEP3148에 정의된 인터페이스와 유사하지만 구현이 다르며 스레드에 바인딩되지 않습니다. 특히 wait() 메서드가 없으므로 사용자는 콜백을 사용하게 됩니다.

저를 포함하여 콜백 함수를 사용하는 것을 좋아하지 않는 사람들을 위해 (Python)은 비동기 I/O 코드를 코루틴으로 작성하기 위한 스케줄러를 제공합니다. 이 스케줄러는 PEP 380의 Yield from 표현식을 사용합니다. 이 스케줄러는 플러그형이 아니며 이벤트 루프 수준에 플러그형이 존재하며 스케줄러는 모든 표준 호환 이벤트 루프 구현에서 작동해야 합니다.

코루틴 및 기타 비동기 프레임워크를 사용하는 코드와의 상호 운용성을 위해 스케줄러에는 Future처럼 작동하는 Task 클래스가 있습니다. 이벤트 루프 수준에서 상호 작용하는 프레임워크는 Future에 콜백 함수를 추가하고 Future가 완료될 때까지 기다릴 수 있습니다. 마찬가지로 스케줄러는 콜백 함수가 호출될 때까지 코루틴을 일시 중단하는 작업을 제공합니다.

이벤트 루프 인터페이스를 통해 스레드 간 상호 작용에 대한 제약 조건을 제공합니다. (Python에서는) 이벤트 루프 호환 Future를 반환할 수 있는 함수를 실행기에 제출할 수 있는 API가 있습니다(PEP 3148 참조).

목적 없음


Stackless Python 또는 greenlets/gevent와 같은 시스템 상호 운용성은 이 튜토리얼의 목적이 아닙니다.

사양


종속성


Python3.3이 필요합니다. Python 3.3의 범위를 넘어서는 새로운 언어나 표준 라이브러리는 필요하지 않습니다. 타사 모듈이나 패키지가 필요하지 않습니다.

모듈 네임스페이스


여기의 사양은 새로운 최상위 패키지에 배치됩니다. 이 패키지의 다양한 하위 모듈에 다양한 구성 요소가 배치됩니다. 패키지는 해당 하위 모듈에서 일반적으로 사용되는 API를 가져와서 패키지 속성으로 사용할 수 있도록 합니다(이메일 패키지가 수행되는 방식과 유사).

최상위 패키지 이름이 아직 지정되지 않았습니다. 참조 구현의 이름은 "tulip"이지만, 이 구현이 표준 라이브러리(Python 3.4에서는 가능)에 추가되면 이 이름이 더 짜증나는 이름으로 변경될 수 있습니다.

귀찮은 이름을 선택하기 전에 이 튜토리얼에서는 최상위 패키지 이름으로 "tulip"을 사용합니다. 주어진 모듈 이름이 없는 클래스와 함수는 최상위 패키지를 통해 액세스한다고 가정합니다.

이벤트 루프 전략: 이벤트 루프 가져오기 및 설정


현재 이벤트 루프를 가져오려면 get_event_loop()를 사용할 수 있습니다. 이 함수는 아래에 정의된 EventLoop 클래스의 인스턴스 또는 동등한 객체를 반환합니다. get_event_loop()는 현재 스레드에 따라 다른 개체를 반환하거나 다른 컨텍스트 개념에 따라 다른 개체를 반환할 수 있습니다.

현재 이벤트 루프를 설정하려면 set_event_loop(event_loop)를 사용할 수 있습니다. 여기서 event_loop는 EventLoop 클래스의 인스턴스이거나 이에 상응하는 인스턴스 객체입니다. 여기서는 get_event_loop()와 동일한 컨텍스트 개념이 사용됩니다.

세 번째 전략 함수인 new_event_loop()도 있는데, 이는 단위 테스트 및 기타 특수 상황에 유용하며 전략의 기본 규칙에 따라 새 EventLoop 인스턴스를 생성하고 반환합니다. 현재 이벤트 루프로 만들려면 set_event_loop()를 호출해야 합니다.

위 세 가지 기능의 작동 방식(컨텍스트 개념 포함)을 변경하려면 set_event_loop_policy(policy)를 호출하면 됩니다. 여기서 매개변수 정책은 이벤트 루프 정책 객체입니다. 이 정책 개체는 위에 설명된 기능(get_event_loop(), set_event_loop(event_loop) 및 new_event_loop())과 유사한 기능을 포함하는 모든 개체일 수 있습니다. 기본 이벤트 루프 정책은 DefaultEventLoopPolicy 클래스의 인스턴스입니다. 현재 이벤트 루프 정책 객체는 get_event_loop_policy()를 호출하여 검색할 수 있습니다.

이벤트 루프 전략은 이벤트 루프가 하나만 존재할 수 있도록 요구하지 않습니다. 기본 이벤트 루프 정책은 이를 강제하지 않지만 스레드당 하나의 이벤트 루프만 있을 수 있도록 강제합니다.

이벤트 루프 인터페이스


시간 정보: Python에서는 모든 시간 초과, 간격 및 지연이 초 단위로 계산되며 정수 또는 부동 소수점일 수 있습니다. 유형. 시계의 정확도는 구현에 따라 다릅니다. 기본값은 time.monotonic()입니다.

콜백 및 핸들러 정보: 함수가 콜백 함수와 여러 변수를 매개변수로 허용하는 경우 콜백 함수를 핸들러 함수 개체(Handler)로 바꿀 수도 있습니다. 이 경우 해당 매개변수를 전달할 필요가 없습니다. 이 핸들러 함수 객체는 지연 반환(fromcall_later())이 아닌 즉시 반환(fromcall_soon())하는 함수여야 합니다. 핸들러가 취소된 경우 이 호출은 아무런 영향을 미치지 않습니다.

표준을 준수하는 이벤트 루프 객체에는

run()과 같은 메서드가 있습니다. 더 이상 할 일이 없을 때까지 이벤트 루프를 실행합니다. 구체적인 의미는

통화 취소 외에는 call_later(), call_repeatedly(), call_soon(), orcall_soon_threadsafe()를 통해 예약된 통화가 더 이상 없습니다.

더 이상 등록된 파일 설명자가 없습니다. 파일 설명자는 닫힐 때 등록 당사자에 의해 등록 취소됩니다.

참고: run()은 종료 조건이 발생하거나 stop()을 호출할 때까지 차단됩니다.

참고: call_repeatedly()를 사용하여 호출을 수행하는 경우 run()은 stop()을 호출하기 전에 종료되지 않습니다.

자세히 설명할 필요: 실제로 얼마나 많은 유사한 작업을 수행해야 합니까?

run_forever(). 이벤트 루프는 stop()이 호출될 때까지 실행됩니다.

run_until_complete(미래, 시간 초과=없음). 이벤트 루프는 Future가 완료될 때까지 실행됩니다. 타임아웃 값이 주어지면 타임아웃 시간 동안 대기합니다. Future가 완료되면 그 결과가 반환되거나 예외가 발생합니다. Future가 시간 초과 전에 완료되거나 stop()이 호출되면 TimeoutError가 발생합니다(그러나 Future는 취소되지 않습니다). 이미 실행 중이므로 이 메서드를 호출할 수 없습니다.

참고: 이 API는 테스트 또는 유사한 작업에 더 많이 사용됩니다. Future를 기다리는 표현식이나 다른 메서드의 산출물을 미래 대체물로 사용해서는 안 됩니다. (예: 완료 콜백 등록)

run_once(시간 초과=없음). 이벤트 세그먼트에 대해 이벤트 루프를 실행합니다. 시간 초과 값이 지정되면 I/O 폴링이 일정 기간 동안 차단됩니다. 그렇지 않으면 I/O 폴링이 시간 제한을 받지 않습니다.

참고: 정확하게 말하면 여기에서 수행되는 작업의 양은 특정 구현에 따라 다릅니다. 한 가지 제약은: call_soon()을 사용하여 자체적으로 직접 예약하는 경우 오류가 발생하고 run_once()가 여전히 반환된다는 것입니다.

중지(). 가능한 한 빨리 이벤트 루프를 중지하십시오. 그런 다음 run()을 사용하여 루프(또는 그 변형)를 다시 시작할 수 있습니다.

참고: 특정 구현에 따라 중지해야 할 블록이 여러 개 있습니다. stop() 이전에 실행 중이던 모든 직접 콜백 함수는 계속 실행 중이어야 하지만, stop() 호출 이후 예약된 콜백 함수(또는 지연된 콜백)는 실행되지 않습니다.

닫기(). 이벤트 루프를 닫고 epoll() 또는 kqueue()에서 사용하는 파일 설명자와 같이 이벤트 루프에 포함된 모든 리소스를 해제합니다. 이벤트 루프가 실행되는 동안에는 이 메서드를 호출하면 안 됩니다. 여러 번 호출할 수 있습니다.

call_later(지연, 콜백, *args). 취소되지 않는 한 호출될 때까지 약 지연 초만큼 콜백(*args)을 예약합니다. 콜백 함수를 나타내기 위해 Handler 객체를 반환합니다. Handler 객체의 cancel() 메서드는 콜백 함수를 취소하는 데 자주 사용됩니다.

call_repeatedly(간격, 콜백, **args). call_later()와 비슷하지만, 반환된 핸들러가 취소될 때까지 콜백 함수가 매 초마다 반복적으로 호출됩니다. 첫 번째 호출은 간격 초 내에 이루어집니다.

call_soon(콜백, *args). call_later(0, 콜백, *args)와 유사합니다.

call_soon_threadsafe(콜백, *args). call_soon(callback, *args)과 비슷하지만 이벤트 루프가 IO를 기다리며 차단되고 다른 스레드에서 호출되면 이벤트 루프 차단이 취소됩니다. 이는 다른 스레드에서 안전하게 호출할 수 있는 유일한 메서드입니다. (스레드 안전 방식으로 지연이 있는 콜백 함수를 예약하려면 ev.call_soon_threadsafe(ev.call_later,when,callback,*args)를 사용할 수 있습니다.) 그러나 신호 처리기에서 호출하는 것은 안전하지 않습니다. 자물쇠를 사용할 수 있습니다.)

add_signal_handler(sig, 콜백, *args). ``sigis'' 신호가 수신될 때마다 callback(*args)이 호출되도록 예약됩니다. 시그널 콜백 함수를 취소하는 데 사용할 수 있는 핸들러를 반환합니다. (반환 핸들러를 취소하면 다음 신호가 도착할 때 Remove_signal_handler()가 호출됩니다. 명시적으로 먼저 Remove_signal_handler()를 호출하십시오.) 이전 핸들러를 대체하려면 동일한 신호에 대해 다른 반환 함수를 정의하십시오. (각 신호는 핸들러로만 활성화될 수 있습니다.) . sig 매개변수는 신호 모듈에 정의된 유효한 신호 값이어야 합니다. 신호를 처리할 수 없는 경우 예외가 발생합니다. 유효한 신호가 아니거나 포착할 수 없는 신호(예: SIGKILL)인 경우 ValueError가 발생합니다. 이 특정 이벤트 루프 인스턴스가 신호를 처리할 수 없는 경우(신호는 프로세서별 전역 변수이므로 기본 스레드의 이벤트 루프만 이러한 신호를 처리할 수 있으므로) RuntimeError가 발생합니다.

remove_signal_handler(sig). 설정 시 신호 서명에 대한 핸들러를 제거합니다. add_signal_handler()와 동일한 예외를 발생시킵니다(좋은 신호를 얻을 수 없는 경우 RuntimeError를 발생시키는 대신 False를 반환하는 것은 제외). 핸들러가 성공적으로 제거되면 True를 반환하고, 핸들러가 설정되지 않으면 False를 반환합니다.

표준 인터페이스를 준수하고 Future를 반환하는 일부 메서드:

wrap_future(future). 이를 위해서는 PEP 3148에 설명된 Future(예: Concurrent.futures.Future 인스턴스)와 이벤트 루프 호환 Future(예: Tulip.Future 인스턴스) 반환이 필요합니다.

run_in_executor(실행자, 콜백, *args). 실행기에서 callback(*args) 호출을 준비합니다(PEP 3148 참조). 반환된 Future의 성공적인 결과는 호출의 반환 값입니다. 이 메서드는 Wrap_future(executor.submit(callback, *args))와 동일합니다. 실행자가 없으면 기본적으로 5개의 스레드를 사용하는 ThreadPoolExecutor가 있습니다.

set_default_executor(executor). run_in_executor()에서 사용하는 기본 실행기를 설정합니다.

getaddrinfo(host, port, family=0, type=0, proto=0, flags=0).socket.getaddrinfo() 함수와 유사하지만 Future를 반환합니다. Future의 성공적인 결과는 소켓.getaddrinfo()의 반환 값과 동일한 형식의 데이터 열입니다. 기본 구현은 run_in_executor()를 통해 소켓.getaddrinfo()를 호출하지만 다른 구현에서는 자체 DNS 조회를 사용하도록 선택할 수도 있습니다. 선택적 인수는 키워드 인수로 지정되어야 합니다.

getnameinfo(sockaddr, flags=0).socket.getnameinfo()와 유사하지만 Future를 반환합니다. Future의 성공적인 결과는 (호스트, 포트)의 배열이 될 것입니다. 잊어버리기()와 동일한 구현을 갖습니다.

create_connection(protocol_factory, 호스트, 포트, **kwargs) 지정된 호스트와 포트를 사용하여 스트리밍 연결을 생성합니다. 이는 링크를 나타내는 전송 종속 구현을 생성한 다음, 사용자의 프로토콜 구현을 인스턴스화(또는 검색)하기 위해 프로토콜_팩토리()를 호출하고 두 개를 함께 바인딩합니다. (아래의 전송 및 프로토콜 정의를 참조하십시오.) 사용자의 프로토콜 구현은 매개변수(*) 없이 프로토콜_팩토리()를 호출하여 생성되거나 검색됩니다. 반환 값은 성공적인 결과가 (전송, 프로토콜) 쌍인 Future입니다. 오류로 인해 성공적인 링크 생성이 차단된 경우 Future에는 적절한 예외 세트가 포함됩니다. 연결 핸드셰이크가 완료된 후 발생하는 Future가 완료되면 프로토콜의 Connection_made() 메서드가 호출되지 않습니다.

(*) 프로토콜_팩토리가 클래스일 필요는 없습니다. 프로토콜 클래스에 정의된 매개변수를 생성자에 전달해야 하는 경우 람다 또는 functool.partial()을 사용할 수 있습니다. 이전에 구성된 프로토콜 인스턴스의 람다를 전달할 수도 있습니다.

선택적 키 매개변수:

family, proto, flags: 주소 패밀리, 프로토콜 및 혼합 플래그 매개변수가 getaddrinfo()에 전달됩니다. 기본값은 모두 0입니다. ((소켓 유형은 항상 SOCK_STREAM입니다.)

ssl: SSL 전송을 생성하려면 True를 전달합니다(기본적으로 일반 TCP로 설정됨). 또는 ssl.SSLConteext 객체를 전달하여 기본값을 재정의합니다. SSL 컨텍스트를 사용합니다. object.

start_serving(protocol_factory, 호스트, 포트, **kwds). 루프가 서비스로 설정되면 완료되는 Future를 반환합니다. 연결이 수신될 때마다 반환 값은 None입니다. 매개변수 없는(*) 프로토콜을 생성하기 위해 프로토콜이 호출되고, 링크의 네트워크 측을 나타내는 전송이 생성되며, 두 객체는 ​​프로토콜.connection_made(transport)

(*)를 호출하여 함께 바인딩됩니다. create_connection()에 대한 보충 설명입니다. 그러나 프로토콜_팩토리()는 들어오는 연결마다 한 번만 호출되므로 새 프로토콜 객체를 호출할 때마다 하나씩 반환하는 것이 좋습니다.

🎜>

family, proto, flags: getaddrinfo()에 전달된 주소 패밀리, 프로토콜 및 혼합 플래그 매개변수는 모두 기본값이 0입니다. ((소켓 유형은 항상 SOCK_STREAM입니다.)

추가: SSL이 지원되나요? (SSL)을 비동기식으로 지원하는 방법을 모르겠습니다. 인증서가 필요합니다.

추가됨: 아마도 Future의 결과 객체를 사용하여 서비스 중지, 모든 활성 연결 종료, (지원되는 경우) 백로그 또는 기타 매개변수 조정과 같은 서비스 루프를 제어할 수 있을까요? 활성 연결을 쿼리하는 API도 있을 수 있습니다. 또한 오류로 인해 루프 제공이 중단되거나 시작할 수 없는 경우 방금 완료되는 Future(하위 클래스?)를 반환합니까? 취소하면 루프가 중지될 수 있습니다.

추가: 일부 플랫폼은 이러한 모든 메서드를 구현하는 데 관심이 없을 수 있습니다. 예를 들어 모바일 앱은 start_serving()에 별로 관심이 없습니다. (내 iPad에 Minecraft 서버가 있지만...)

파일 설명자에 대한 콜백 함수를 등록하는 다음 방법은 필요하지 않습니다. 이러한 메서드가 구현되지 않은 경우 해당 메서드에 액세스할 때(호출하는 대신) AttributeError가 반환됩니다. 기본 구현에서는 이러한 메서드를 제공하지만 일반적으로 사용자는 이를 직접 사용하지 않고 전송 계층에서만 독점적으로 사용합니다. 마찬가지로 Windows 플랫폼에서는 이러한 메서드가 반드시 구현되지는 않습니다. 선택 또는 IOCP 이벤트 루프 모델이 사용되는지 여부에 따라 다릅니다. 두 모델 모두 fileno() 메서드에서 반환된 객체 대신 정수 파일 설명자를 허용합니다. 파일 설명자는 쿼리 가능한 것이 좋습니다. 예를 들어 디스크 파일은 쿼리할 수 없습니다.

add_reader(fd, callback, *args). 파일 설명자 fd가 읽기 작업 준비가 되면 지정된 콜백 함수 callback(*args)를 호출합니다. 콜백 함수를 취소하는 데 사용할 수 있는 핸들러 함수 개체를 반환합니다. call_later()와 달리 이 콜백 함수는 여러 번 호출될 수 있습니다. 동일한 파일 설명자에서 add_reader()를 다시 호출하면 이전에 설정된 콜백 함수가 취소됩니다. 참고: 취소 핸들러는 핸들러 함수가 호출될 때까지 기다릴 수 있습니다. fd를 닫으려면 Remove_reader(fd)를 호출해야 합니다. (TODO: 핸들러 함수가 설정된 경우 예외를 발생시킵니다.)

add_writer(fd, callback, *args) add_reader()와 유사하지만 쓰기 작업을 수행하기 전에 콜백 함수가 호출됩니다.

remove_reader(fd). 파일 설명자 fd에 설정된 읽기 작업 콜백 함수를 제거합니다. 콜백 함수가 설정되어 있지 않으면 아무런 작업도 수행되지 않습니다. (이러한 대체 인터페이스를 제공하는 이유는 녹음 파일 설명자가 녹음 처리 기능보다 더 편리하고 간단하기 때문입니다.) 삭제에 성공하면 True를 반환하고, 실패하면 False를 반환합니다.

remove_writer(fd). 파일 설명자 fd에 설정된 쓰기 작업 콜백 함수를 제거합니다.

미완성: 파일 설명자에 여러 콜백 함수가 포함되어 있으면 어떻게 해야 합니까? 현재 메커니즘은 이전 콜백 함수를 대체하는 것이며, 콜백 함수가 등록된 경우 예외가 발생해야 합니다.

다음 방법은 소켓 비동기 I/O에서 선택 사항입니다. 위에서 언급한 선택적 메서드에 대한 대안으로, Windows의 전송 구현에서 IOCP를 사용하기 위한 것입니다(이벤트 루프가 이를 지원하는 경우). 소켓 매개변수는 소켓을 차단해서는 안 됩니다.

sock_recv(양말, n). 소켓 양말에서 바이트를 받습니다. 성공 시 바이트열 객체가 될 Future를 반환합니다.

sock_sendall(양말, 데이터). 소켓 소켓에 데이터 바이트를 보냅니다. Future를 반환합니다. 성공하면 Future의 결과는 None이 됩니다. (추가: sendall() 또는 send()를 에뮬레이트하는 것이 더 나을까요? 하지만 제 생각에는 sendall() - 이름을 send()로 지정해야 할까요?)

sock_connect(sock, address) . 주어진 주소에 접속하세요. Future를 반환합니다. Future의 성공적인 결과는 None입니다.

sock_accept(양말). 소켓에서 링크를 받습니다. 소켓은 청취 모드에 있어야 하며 사용자 정의 소켓에 바인딩되어야 합니다. Future를 반환합니다. Future의 성공적인 결과는 (conn, Peer)의 배열이 됩니다. 여기서 conn은 연결된 비차단 소켓이고 피어는 피어 주소입니다. (사이드바: 사람들은 이 API 스타일이 높은 수준의 서버에서는 매우 느리다고 말합니다. 그래서 위에 start_sering()이 있습니다. 이것이 여전히 필요한가요?)

사이드바: 선택적 방법 중 어느 것도 그다지 좋지 않습니다. 어쩌면 이것들이 모두 필요할까요? 여전히 플랫폼의 보다 효율적인 설정에 의존합니다. 또 다른 가능성은 문서에 이러한 항목은 "전송에만 사용 가능"하고 다른 항목은 "어떠한 경우에도 사용 가능"하다고 명시되어 있다는 것입니다.

콜백 순서


두 개의 콜백 함수가 동시에 예약된 경우 등록된 순서대로 실행됩니다. 예:

ev.call_soon(foo)

ev.call_soon(bar)

은 foo()가 bar()에서 실행되도록 보장합니다.

call_soon()을 사용하면 시스템 시계가 거꾸로 되더라도 이 보장은 계속 유지됩니다. 이는 call_later(0,callback,*args)에도 적용됩니다. 그러나 시스템 시계가 거꾸로 가고 있을 때 지연 시간 없이 call_later()를 사용하면 보장할 수 없습니다. (좋은 이벤트 루프 구현은 시스템 시계 역행 상황으로 인해 발생하는 문제를 피하기 위해 time.monotonic()을 사용해야 합니다. PEP 418을 참조하세요.)

Context


모든 이벤트 루프에는 컨텍스트라는 개념이 있습니다. 기본 이벤트 루프 구현의 경우 컨텍스트는 스레드입니다. 이벤트 루프 구현은 동일한 컨텍스트에서 모든 콜백을 실행해야 합니다. 이벤트 루프 구현은 한 번에 하나의 콜백만 실행해야 하므로 콜백은 동일한 이벤트 루프에 예약된 다른 콜백으로부터 자동 상호 배제를 유지하는 역할을 합니다.

예외


Python에는 Exception 클래스에서 파생된 예외와 BaseException에서 파생된 예외라는 두 가지 유형의 예외가 있습니다. Exception에서 파생된 예외는 일반적으로 적절하게 포착되고 처리됩니다. 예를 들어 예외는 Future를 통해 전달되고 콜백 내에서 발생하면 기록되고 무시됩니다.

그러나 BaseException의 예외는 포착되지 않습니다. 일반적으로 오류 추적을 전달하고 프로그램을 종료시킵니다. (예에는 KeyboardInterrupt 및 SystemExit가 포함됩니다. 이러한 예외를 대부분의 다른 예외와 마찬가지로 처리하는 것은 현명하지 않습니다.)

핸들러 클래스


등록을 나타내는 객체를 반환하는 콜백 함수(예: call_later())를 등록하는 다양한 방법이 있습니다. 객체를 사용하여 콜백 함수를 취소할 수 있습니다. 사용자는 이 클래스를 인스턴스화할 필요가 없지만 여전히 이 객체에 Handler라는 좋은 이름을 부여하고 싶어합니다. 이 클래스에는

cancel()이라는 공개 메서드가 있습니다. 콜백 함수를 취소해 보세요. 보충: 정확한 사양.

읽기 전용 공개 속성:

콜백. 호출할 콜백 함수입니다.

args. 콜백 함수를 호출하기 위한 매개변수 배열입니다.

취소되었습니다. cancel() 테이블이 호출되면 해당 값은 True입니다.


일부 콜백 함수(예: call_later()를 통해 등록된 함수)는 한 번만 호출된다는 점에 유의해야 합니다. 다른 것(add_reader()를 통해 등록된 것과 같은)은 여러 번 호출되도록 되어 있습니다.

보충: 콜백 함수 호출을 위한 API(예외 처리를 캡슐화해야 합니까)? 호출 횟수를 기록해야 합니까? 어쩌면 이 API는 _call_()과 같아야 할까요? (단, 예외는 억제해야 합니다.)

추가: 콜백 함수가 예약될 때 실시간 값을 기록하는 공용 속성이 있나요? (왜냐하면 힙에 저장하는 방법이 필요하기 때문입니다.)

Futures


ulip.Future는 PEP 3148 .futures와 동시에 작동하도록 특별히 설계되었습니다. .미래는 비슷하지만 약간의 차이가 있습니다. 이 PEP에서 Future가 언급될 때마다 Concurrent.futures.Future로 명시적으로 지정되지 않는 한 튤립.Future를 참조합니다. Tulip.Future에서 지원하는 공개 API는 다음과 같으며 PEP 3148과의 차이점도 지적됩니다.

cancel() Future가 완료(또는 취소)되면 False를 반환합니다. 그렇지 않으면 Future의 상태를 취소된 상태(완료라고도 이해할 수 있음)로 변경하고 콜백 함수를 예약하고 True를 반환합니다.

cancelled(). Future가 취소된 경우 True를 반환합니다.

running()은 항상 False를 반환합니다. PEP 3148과 달리 실행 상태가 없습니다.

done(). Future가 완료되면 True를 반환합니다. 참고: 취소된 Future도 완료된 것으로 간주됩니다(여기서나 다른 곳에서나 마찬가지입니다).

result(). set_result()로 설정된 결과를 반환하거나, set_Exception()으로 설정된 예외를 반환합니다. 취소된 경우 CancelledError가 발생합니다. PEP 3148과 달리 시간 초과 매개변수와 대기가 없습니다. Future가 아직 완료되지 않은 경우 예외가 발생합니다.

Exception(). 위와 동일하며 예외를 반환합니다.

add_done_callback(fn) Future가 완료(또는 취소)될 때 실행되는 콜백 함수를 추가합니다. Future가 완료(또는 취소)된 경우 call_soon()을 사용하여 콜백 함수를 전달합니다. PEP 3148과 달리 추가된 콜백 함수는 즉시 호출되지 않고 항상 호출자의 컨텍스트에서 실행됩니다. (일반적으로 컨텍스트는 스레드입니다.) call_soon()을 사용하여 콜백 함수를 호출하는 것으로 이해하시면 됩니다. 참고: 추가된 콜백 함수(이 PEP의 다른 콜백 함수와 다르며 아래 "콜백 스타일" 섹션의 규칙을 무시함)는 항상 Future를 매개변수로 수신하며 이 콜백 함수는 핸들러 객체가 아니어야 합니다.

set_result(result). 이 Future는 완료(또는 취소) 상태일 수 없습니다. 이 메서드는 현재 Future를 완료 상태로 설정하고 관련 콜백 함수 호출을 준비합니다. PEP 3148과 달리 이는 공개 API입니다.

set_Exception(예외). 위와 동일하며 예외를 설정합니다.

내부 메소드 set_running_or_notify_cancel()은 더 이상 지원되지 않습니다. 이를 실행 상태로 직접 설정할 수 있는 방법이 없습니다.

이 PEP는 다음 예외를 정의합니다:

InvalidStateError. 이 예외는 호출된 메서드가 이 Future의 상태를 허용하지 않을 때 발생합니다(예: 완료된 Future에서 set_result( ) 메서드를 사용하거나, 완료되지 않은 Future에서 result() 메서드를 호출하세요.

InvalidTimeoutError. result() 또는 예외()를 호출할 때 0이 아닌 인수가 전달되면 이 예외가 발생합니다.

Concurrent.futures.CancelledError의 별칭인 CancelledError. 이 예외는 취소된 Future에 대해 result() 또는 예외() 메서드가 호출될 때 발생합니다.

Concurrent.futures.TimeoutError의 별칭. EventLoop.run_until_complete() 메소드에 의해 발생할 수 있습니다.

Future를 생성하면 기본 이벤트 루프와 연결됩니다. (아직 완료되지 않았습니다. 이벤트 루프를 인수로 전달하도록 허용하시겠습니까?)

concurrent.futures 패키지의 wait() 및 as_completed() 메서드는 튤립.Future 객체를 매개변수로 허용하지 않습니다. 그러나 아래에 설명된 유사한 API인 Tulip.wait() 및 Tulip.as_completed()가 있습니다.

Tulip.Future 개체를 적용하여 서브루틴(코루틴)의 표현식을 생성할 수 있습니다. 이는 Future의 __iter__() 인터페이스를 통해 구현됩니다. 아래의 "서브루틴 및 스케줄러" 섹션을 참조하세요.

Future 객체가 재활용될 때 연관된 예외가 있지만 result(), 예외() 또는 __iter__() 메서드가 호출되지 않은 경우(또는 예외가 생성되었지만 아직 발생하지 않은 경우) 그런 다음 이 예외가 기록되어야 합니다. TBD: 어느 정도 수준으로 기록되나요?

미래에는 Tulip.Future와 Concurrent.futures.Future를 통합할 수도 있습니다. 예를 들어 표현식에서 산출물을 지원하려면 후자의 객체에 __iter__() 메서드를 추가하세요. 이벤트 루프가 실수로 완료되지 않은 result()를 호출하여 이벤트 루프를 차단하는 것을 방지하려면 차단 메커니즘이 현재 스레드에 활성 이벤트 루프가 있는지 감지해야 합니다. 그렇지 않으면 예외가 발생합니다. 그러나 이 PEP는 외부 종속성(Python3.3에만 의존)을 최소화하는 것을 목표로 하므로 현재는 Concurrent.futures.Future에 대한 변경 사항이 없습니다.

전송 계층


전송 계층은 소켓 또는 기타 유사한 메커니즘(예: 파이프 또는 SSL 연결)을 기반으로 하는 추상화 계층을 나타냅니다. 여기의 전송 계층은 Twisted 및 PEP 3153의 영향을 많이 받습니다. 사용자가 전송 계층을 직접 구현하거나 인스턴스화하는 경우는 거의 없습니다. 이벤트 루프는 전송 계층 설정을 위한 관련 방법을 제공합니다.

전송 계층은 프로토콜 작업에 사용됩니다. 일반적인 프로토콜은 기본 전송 계층의 특정 세부 사항에 관심이 없으며 전송 계층을 사용하여 다양한 프로토콜과 작업할 수 있습니다. 예를 들어, HTTP 클라이언트 구현은 일반 소켓 전송 계층을 사용하거나 SSL 전송 계층을 사용할 수 있습니다. 일반 소켓 전송 계층은 HTTP 프로토콜 외부의 수많은 프로토콜(예: SMTP, IMAP, POP, FTP, IRC, SPDY)과 작동할 수 있습니다.

대부분의 연결은 비대칭적 특성을 가지고 있습니다. 즉, 클라이언트와 서버는 일반적으로 서로 다른 역할과 동작을 갖습니다. 따라서 전송 계층과 프로토콜 간의 인터페이스도 비대칭입니다. 프로토콜 관점에서 데이터 전송은 전송 계층 객체의 write() 메서드를 호출하여 수행됩니다. write() 메서드는 데이터를 버퍼에 넣은 후 즉시 반환합니다. 데이터를 읽을 때 전송 계층은 보다 적극적인 역할을 수행합니다. 즉, 소켓(또는 다른 데이터 소스)에서 데이터를 수신한 후 전송 계층은 프로토콜의 data_received() 메서드를 호출합니다.

전송 계층에는 다음과 같은 공개 메소드가 있습니다:

write(data). 매개변수는 바이트열 객체여야 합니다. 없음을 반환합니다. 전송 계층은 데이터 바이트를 자유롭게 캐시할 수 있지만 데이터가 다른 쪽 끝으로 전송되고 데이터 흐름 동작이 유지되는지 확인해야 합니다. 즉, t.write(b'abc'); t.write(b'def')는 t.write(b'abcdef')와 동일하며 다음과 같습니다.

t.write(b 'a')

t.write(b'b')

t.write(b'c')

t.write(b'd')

t.write(b'e')

t.write(b'f')

writelines(iterable)와 동일:

data in iterable:

self.write(data)

write_eof(). 쓰기 데이터 끝의 연결을 닫으면 write() 메서드를 더 이상 호출할 수 없습니다. 버퍼링된 모든 데이터가 전송되면 전송 계층은 더 이상 데이터가 없다는 신호를 상대방에게 보냅니다. 일부 프로토콜은 이를 지원하지 않습니다. 이 경우 write_eof()를 호출하면 예외가 발생합니다. (참고: 이 메서드는 이전에 half_close()라고 했습니다. 구체적인 의미를 모르는 경우 이 메서드 이름은 어느 끝이 닫힐지 명확하게 나타내지 않습니다.)

can_write_eof() 프로토콜이 write_eof()를 지원하는 경우. 이면 True를 반환하고, 그렇지 않으면 False를 반환합니다. (write_eof()를 사용할 수 없는 경우 일부 프로토콜에서는 해당 동작을 변경해야 하므로 이 방법이 필요합니다. 예를 들어 HTTP에서 현재 크기를 알 수 없는 데이터를 전송하려면 일반적으로 write_eof()를 사용하여 그러나 SSL은 이 동작을 지원하지 않습니다. 해당 HTTP 프로토콜 구현은 청크 인코딩을 사용해야 합니다. 그러나 전송 시 데이터 크기를 알 수 없는 경우 두 경우 모두에 대한 최상의 솔루션을 사용하는 것입니다. Content-Length 헤더 )

pause(). 데이터 전송을 일시 중지하고 이력서() 메서드를 직접 호출합니다. Pause() 호출과 Resume() 호출 사이에 프로토콜의 data_received() 메서드는 다시 호출되지 않습니다. write() 메소드에서는 유효하지 않습니다.

resume(). 프로토콜의 data_received()를 사용하여 데이터 전송을 재개합니다.

close()를 닫습니다. write()를 사용하여 버퍼링된 모든 데이터가 전송될 때까지 연결은 닫히지 않습니다. 연결이 닫힌 후에는 프로토콜의 data_received() 메서드가 더 이상 호출되지 않습니다. 버퍼링된 모든 데이터가 전송되면 프로토콜의 Connection_lost() 메서드가 None을 매개변수로 사용하여 호출됩니다. 참고: 이 메서드는 위의 모든 메서드가 호출된다는 것을 보장하지 않습니다.

abort() 연결을 중단합니다. 아직 전송되지 않은 버퍼의 모든 데이터는 삭제됩니다. 잠시 후 프로토콜의 Connection_lost()가 호출되어 None 매개변수를 전달합니다. (미정: close(), abort() 또는 다른 쪽 끝의 닫기 작업에서 다른 매개변수를 Connection_lost()에 전달합니까? 아니면 이를 쿼리하기 위해 특별히 메서드를 추가합니까? Glyph는 다른 예외를 전달할 것을 권장합니다.)

아직 완료되지 않음: 다른 흐름 제어 방법을 제공합니다. 버퍼 데이터가 부담이 되면 전송 계층이 프로토콜 계층을 일시 중지할 수 있습니다. 권장 사항: 프로토콜에 포즈() 및 재개() 메서드가 있는 경우 전송 계층에서 해당 메서드를 호출하도록 허용하세요. 해당 메서드가 없으면 프로토콜은 흐름 제어를 지원하지 않습니다. (pause()와 재개()의 경우 프로토콜 계층과 전송 계층의 이름을 다르게 사용하는 것이 더 나을 수도 있겠죠?)

프로토콜


프로토콜은 일반적으로 전송 계층과 함께 사용됩니다. 여기에는 일반적으로 사용되는 몇 가지 프로토콜(예: 몇 가지 유용한 HTTP 클라이언트 및 서버 구현)이 제공되며, 대부분을 구현하려면 사용자 또는 타사 라이브러리가 필요합니다.

프로토콜은 전송 계층에서 호출되는 다음 메서드를 구현해야 합니다. 이러한 콜백 함수는 올바른 컨텍스트에서 이벤트 루프에 의해 호출됩니다(위의 "컨텍스트" 섹션 참조).

connection_made(transport). 전송 계층이 준비되었으며 구현의 다른 쪽 끝에 연결되었음을 의미합니다. 프로토콜은 전송 계층 참조를 변수로 저장해야 하며(write() 및 기타 메서드를 나중에 호출할 수 있도록) 이때 핸드셰이크 요청을 보낼 수도 있습니다.

data_received(data). 전송 계층이 데이터의 일부를 읽었습니다. 매개변수는 비어 있지 않은 바이트열 객체입니다. 이 매개변수의 크기에는 명시적인 제한이 없습니다. p.data_received(b'abcdef')는 다음 명령문과 동일해야 합니다:

p.data_received(b'abc')

p.data_received(b'def')

eof_received(). 이 메서드는 write_eof() 또는 다른 동등한 메서드가 상대방에서 호출될 때 호출됩니다. 기본 구현에서는 프로토콜의 Connection_lost() 메서드를 호출하는 전송 계층의 close() 메서드를 호출합니다.

connection_lost(exc). 전송 계층이 닫혔거나 중단되었거나, 다른 쪽 끝이 연결을 안전하게 닫았거나 예외가 발생했습니다. 처음 세 가지 경우에서 매개변수는 None입니다. 예외의 경우 매개변수는 전송 계층을 중단시킨 예외입니다. (미정: 처음 세 가지 상황을 다르게 처리해야 합니까?)

다음은 호출의 순서와 다양성을 보여주는 다이어그램입니다.

connection_made()-- 정확히 한 번

data_received()-- 0회 이상

eof_received()-- 최대 한 번

connection_lost()-- 정확히 한 번

추가: 사용자의 코드 프로토콜과 전송 프로토콜이 조기에 GC(가비지 수집)되지 않도록 조치를 취해야 합니다.

콜백 함수 스타일


대부분의 인터페이스는 콜백 함수와 위치 매개변수도 사용합니다. 예를 들어 foor("abc",42)가 즉시 호출되도록 예약하려면 ev.call_soon(foo,"abc",42)를 호출합니다. foo() 호출을 예약하려면 ev.call_soon(foo)을 사용하세요. 이 규칙은 일반적인 콜백 함수 프로그래밍에 필요한 작은 람다 식의 수를 크게 줄입니다.

이 규칙은 명시적으로 키워드 인수를 지원하지 않습니다. 키워드 인수는 콜백 함수에 대한 선택적 추가 정보를 전달하는 데 자주 사용됩니다. 이를 통해 호출자가 키워드를 어딘가에 선언했는지 여부에 대해 걱정할 필요 없이 API를 우아하게 수정할 수 있습니다. 키워드 인수로 호출해야 하는 콜백 함수가 있는 경우 람다 표현식 또는 functools.partial을 사용할 수 있습니다. 예:

ev.call_soon(functools.partial(foo, "abc",peat=42))


이벤트 루프 구현 선택

완료 예정입니다. (select/poll/epoll 사용 및 선택 변경 방법에 대한 내용입니다. 이벤트 루프 전략에 속합니다.)

코루틴 및 스케줄러


이것은 독립 상태는 이벤트 루프 인터페이스와 다르기 때문에 최상위 부분입니다. 코루틴은 선택 사항이며 콜백을 사용하여 코드를 작성하는 것이 좋습니다. 반면에 스케줄러/코루틴 API 구현은 하나만 있으며, 코루틴을 선택하면 그 API만 사용하게 됩니다.

코루틴


코루틴은 다음 규칙을 따르는 생산자입니다. 좋은 문서화를 위해 모든 코루틴은 @tulip.coroutine으로 장식되어야 하지만 이것이 반드시 필요한 것은 아닙니다.

코루틴은 원래 Yield 구문 대신 PEP 380에 도입된 Yield from 구문을 사용합니다.

"코루틴"이라는 단어는 "생산자"와 비슷한 의미를 가지며 두 가지 서로 다른(비록 관련이 있는) 개념을 설명하는 데 사용됩니다.

은 코루틴 함수(tulip.coroutine 수정을 사용하여 정의된 함수)를 정의합니다. 명확하게 하기 위해 이 함수를 코루틴 함수라고 부를 수 있습니다.

코루틴을 통해 객체를 얻습니다. 이 개체는 최종적으로 완료될 계산 또는 I/O 작업(일반적으로 둘 다)을 나타냅니다. 모호함을 없애기 위해 이 객체를 코루틴 객체라고 부를 수 있습니다.


코루틴이 할 수 있는 작업:

결과 = 미래의 Yield를 사용합니다. 미래가 완료될 때까지 코루틴을 일시 중지한 다음 future 의 결과 또는 전달하려는 예외를 발생시킵니다.

결과 = 코루틴의 Yield를 사용합니다. 다른 코루틴이 결과를 생성할 때까지 기다립니다(또는 전달될 예외를 발생시킵니다). 이 코루틴의 예외는 다른 코루틴에 대한 호출이어야 합니다.

결과 반환--yield from 표현식을 사용하여 결과를 기다리는 코루틴에 대한 결과를 반환합니다.

예외 발생 - Yield from 표현식을 사용하여 대기 중인 (프로그램)에 대해 코루틴에서 예외를 발생시킵니다.

코루틴을 호출해도 해당 코드가 즉시 실행되지는 않습니다. 이는 단지 생산자일 뿐이며 호출에 의해 반환된 코루틴은 실제로는 반복할 때까지 아무 작업도 수행하지 않는 생산자 개체일 뿐입니다. 코루틴의 경우 실행을 시작하는 두 가지 기본 방법이 있습니다. 다른 코루틴에서 Yield를 호출하거나(다른 코루틴이 이미 실행 중이라고 가정!) 작업으로 변환합니다(아래 참조).

코루틴은 이벤트 루프가 실행 중일 때만 실행될 수 있습니다.

여러 코루틴 대기


유사한 wait()와 as_completed()가 두 개 있으며, Concurrent.futures 패키지의 API는 여러 코루틴을 기다리는 기능을 제공합니다. 코루틴 코루틴 또는 Future:

tulip.wait(fs, timeout=None, return_when=ALL_COMPLETED). 이는 Future 또는 다른 코루틴이 완료되기를 기다리는 fs에서 제공하는 코루틴입니다. 코루틴 매개변수는 작업에 캡슐화됩니다(아래 참조). 이 메소드는 Future를 반환합니다. Future의 성공적인 결과는 두 개의 Future 세트(완료, 보류 중)를 포함하는 튜플입니다. done은 원래 Future(또는 캡슐화된 코루틴)이고 보류는 휴식을 의미합니다. 아직 완료되지 않았습니다(또는 취소). 선택적 매개변수인 timeout 및 return_when은 Concurrent.futures.wait()의 매개변수와 동일한 의미 및 기본값을 갖습니다. timeout은 None이 아닌 경우 모든 작업에 대한 시간 제한을 지정하고, return_when은 중지할 시기를 지정합니다. FIRST_COMPLETED, FIRST_EXCEPTION, ALL_COMPLETED 상수는 동일한 값 정의를 사용하고 PEP 3148에서 동일한 의미를 갖습니다.

ALL_COMPLETED(기본값): 모든 Future가 처리되거나 완료될 때까지(또는 시간 초과가 발생할 때까지) 기다립니다.

FIRST_COMPLETED: 하나 이상의 Future가 완료되거나 취소될 때까지(또는 시간 초과가 발생할 때까지) 기다립니다.

FIRST_EXCEPTION: 예외로 인해 하나 이상의 Future가 준비(취소되지 않음)될 때까지 기다립니다(취소된 Future를 필터에서 제외하는 것은 마술이지만 PEP 3148은 이런 방식으로 수행합니다).

tulip.as_completed(fs, timeout=None). Future 값을 가진 반복자를 반환하고 fs에서 다음 Future 또는 코루틴이 완료될 때까지 성공적인 값을 기다리며 자체 결과를 반환합니다(또는 예외 발생). . 선택적 매개변수인 timeout은 Concurrent.futures.wait()의 매개변수와 동일한 의미 및 기본값을 갖습니다. 시간 초과가 발생하면 반복자가 반환하는 다음 Future는 기다리는 동안 TimeoutError 예외를 발생시킵니다. 사용 예:

for f in as_completed(fs):

result = Yield from f # 예외가 발생할 수 있습니다.

# 결과를 사용합니다.


태스크


태스크는 독립적으로 실행되는 서브루틴을 관리하는 객체입니다. Task 인터페이스와 Future 인터페이스는 동일합니다. 서브루틴이 완료되거나 예외가 발생하면 이와 관련된 작업도 완료됩니다. 반환된 결과는 해당 작업의 결과이고, 던져진 예외는 해당 작업의 예외입니다.

완료되지 않은 작업을 취소하면 관련 서브루틴이 계속 실행되지 않습니다. 이 경우 서브루틴은 취소 명령을 더 잘 처리하기 위해 예외를 수신합니다. 물론 서브루틴은 이 예외를 처리할 필요가 없습니다. 이 메커니즘은 PEP 342에 설명된 생성기의 표준 close() 메서드를 호출하여 수행됩니다.

작업은 서브루틴과 Twisted와 같은 콜백 기반 프레임워크 간의 상호작용에도 유용합니다. 서브루틴을 작업으로 변환한 후 작업에 콜백 함수를 추가할 수 있습니다.

왜 모든 서브루틴을 작업으로 변환하지 않습니까? @tulip.coroutinedesignator가 이 작업을 수행할 수 있습니다. 이 경우 서브루틴이 다른 서브루틴(또는 기타 복잡한 상황)을 호출하면 전체 프로그램이 상당히 느려집니다. 복잡한 상황에서는 서브루틴을 작업으로 변환하는 것보다 유지하는 것이 훨씬 빠릅니다.

스케줄러


스케줄러에는 공개 인터페이스가 없습니다. 미래 및 작업 산출량을 사용하여 스케줄러와 상호 작용할 수 있습니다. 실제로 스케줄러에는 특정 클래스 구현이 없습니다. Future 및 Task 클래스는 이벤트 루프의 공개 인터페이스를 사용하여 스케줄러의 동작을 나타냅니다. 따라서 타사 이벤트 루프 구현으로 변경하더라도 스케줄러 기능을 계속 사용할 수 있습니다.

Sleep


미완성: sleep(0)을 사용하여 I/O를 일시 중지하고 쿼리할 수 있습니다.

코루틴과 프로토콜


코루틴을 사용하여 프로토콜을 구현하는 가장 좋은 방법은 data_received()를 사용하는 스트림 캐시를 사용하는 것입니다. 동시에 Future를 반환하는 read(n) 및 readline()과 같은 메서드를 사용하여 데이터를 비동기적으로 읽을 수 있습니다. 연결이 닫히면 read() 메서드는 결과가 ''인 Future를 반환해야 하며, 예외로 인해 Connection_closed()가 호출되면 예외를 발생시켜야 합니다.

데이터를 쓰려면 전송에서 write()(및 유사한) 메서드를 사용할 수 있습니다. 이 메서드는 Future를 반환하지 않습니다. Connection_made()가 호출될 때 코루틴을 설정하고 시작하기 위한 표준 프로토콜 구현이 제공되어야 합니다.

추가됨: 더 많은 사양.

취소


보충. 작업이 취소되면 해당 코루틴은 스케줄러에서 중단될 때마다(예: 작업 도중에 중단될 수 있음) 예외를 확인합니다. 어떤 예외를 던질 것인지 명확하게 해야 합니다.

다시 추가됨: 시간 초과.

알려진 문제


디버깅 API? 예를 들어 많은 것을 기록하거나 흔하지 않은 조건(예: 대기열을 비우는 것보다 빠르게 채우는 것)을 기록하는 것, 심지어 시간이 많이 걸리는 콜백 함수 등...

자세한 API가 필요합니까? 예를 들어 요청 읽기 콜백 함수는 파일 설명자를 반환합니다. 또는 다음 예정된 콜백 함수가 호출될 때. 또는 콜백 함수에 의해 등록된 일부 파일 설명자.

전송에는 소켓의 주소를 반환하려고 시도하는 메서드(및 동등한 주소를 반환하는 다른 메서드)가 필요할 수 있습니다. 이는 소켓 유형에 따라 다르지만 항상 소켓이 아닌 경우 None이 반환되어야 합니다. (또는 소켓 자체를 반환하는 메서드가 있을 수 있지만 IP 링크를 구현하기 위해 소켓을 사용하지 않을 수도 있으므로 어떻게 해야 할까요?)

os.fokd()를 처리해야 합니다. (튤립의 경우 선택기 클래스까지 올라갈 수 있습니다.)

start_serving()에는 현재 소켓을 전달하기 위한 메서드가 필요할 수 있습니다(예를 들어 gunicorn에는 이 메서드가 필요합니다). create_connection()에도 동일한 문제가 있습니다.

사용하기가 약간 힘들긴 하지만 몇 가지 명시적 잠금을 도입할 수도 있습니다. with lock: block 구문을 사용할 수 없기 때문입니다(잠금을 기다리려면 항복을 사용해야 합니다. with 문은 수행할 수 없습니다).

데이터그램 프로토콜 및 링크 지원 여부. sock_sendto() 및 sock_recvfrom()과 같은 더 많은 소켓 I/O 메서드가 있을 수 있습니다. 또는 사용자 클라이언트가 직접 작성합니다(이것은 로켓 과학이 아닙니다). write(), writelines(), data_received()를 단일 데이터그램으로 재정의할 이유가 있습니까? (Glyph에서는 후자를 권장합니다.) 그렇다면 write() 대신 무엇을 사용해야 할까요? 마지막으로, 비연결 데이터그램 프로토콜을 지원해야 합니까? (이것은 sendto() 및 recvfrom()을 캡슐화한다는 의미입니다.)

다양한 슈퍼마켓을 제어하려면 API가 필요할 수 있습니다. 예를 들어 DNS, 연결, SSL 핸드셰이크, 유휴 연결 또는 각 세션을 해결하는 데 소요되는 시간을 제한할 수 있습니다. 아마도 일부 메서드에 timeout 키워드 인수를 완전히 추가하고 다른 메서드는 call_later 및 Task.cancel()을 통해 영리하게 시간 초과를 구현하는 방법이 있을 것입니다. 그러나 기본 시간 제한이 필요한 메서드가 있을 수 있으며 이 사양의 전역 작업에 대한 기본값을 변경하고 싶을 수도 있습니다. (예: 모든 이벤트 루프)

NodeJS 스타일 이벤트 트리거? 아니면 별도의 튜토리얼로 만드시겠습니까? 이는 표준화에서 수행하는 것이 더 나을 수도 있지만 실제로는 사용자 공간에서 수행하기에 충분히 쉽습니다(https://github.com/mnot/thor/blob/master/thor/events.py 및 https://github 참조). .com /mnot/thor/blob/master/doc/events.md )


참조


PEP 380 TBD에서: Greg Ewing의 튜토리얼은 수율의 의미를 설명합니다.

PEP 3148은 동시.futures.Future를 설명합니다.

PEP 3153은 거부되었지만 전송과 프로토콜을 분리해야 할 필요성을 잘 설명합니다.

Tulip repo: http://code.google.com/p/tulip/

Nick Coghlan이 비동기 I/O가 다른 처리와 관련하여 작성한 좋은 블로그 항목입니다. gevent 및 wihle, for, with와 같은 미래 개념을 사용하는 방법에 대한 아이디어: http://python-notes.boredomandlaziness.org/en/latest/pep_ideas/async_programming.html

미정: 다음에 대한 참고 자료 Twisted, Tornado, ZeroMQ, pyftpdlib, libevent, libev, pyev, libuv, wattle 등

감사의 글


PEP 3153 외에도 다음의 영향을 받았습니다. 영향에는 PEP 380 및 Twisted, Tornado, ZeroMQ, pyftpdlib, 튤립(이 모든 것을 결합하려는 저자의 시도), wattle(Steve Dower의 반대 제안)에서 생성되는 Greg Ewing의 튜토리얼이 포함됩니다. 2012년 9월 12월까지 Python 아이디어에 대한 많은 토론, Steve Dower 및 Dino Viehland와의 Skype 세션 Ben Darnell과의 이메일 교환, Niels Provos(libevent의 원저자)의 청취자, 두 개의 쇼 및 여러 Twisted 개발자 Glyph, Brian Warner, 데이비드 리드, 던컨 맥그리거. 마찬가지로 저자도 초기 단계에서 Google App Engine NDB 라이브러리의 비동기 지원에 중요한 영향을 미쳤습니다.


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.