4

두 클래스는 동시 프로그래밍의 뛰어난 추상화를 나타내므로 동일한 API를 지원하지 않는다는 것이 당황 스럽습니다. docs에 따라 구체적asyncio.Future가 concurrent.futures.Future와 호환되지 않는 이유는 무엇입니까?

:

asyncio.Futureconcurrent.futures.Future은 거의 호환된다.

차이 :

  • result()exception() 시간 초과 인수를 미래가 아직 완료되지 않은 경우 예외를 발생하지 않습니다.
  • add_done_callback()으로 등록 된 콜백은 항상 이벤트 루프의 call_soon_threadsafe()을 통해 호출됩니다.
  • 이 클래스는 concurrent.futures 패키지의 wait()as_completed() 함수와 호환되지 않습니다.

위의 목록은 몇 가지 더 차이가있다, 실제로 불완전 : 너무 일찍 전화하면

  • running() 방법은 InvalidStateError을 제기 할 수
  • result()exception() 결석

이러한 작업은 이벤트 루프가 본질적으로 유용하기 때문에 이러한 작업이 쓸모 없거나 구현하기에 너무 번거롭습니까?

그리고 add_done_callback()과 관련된 차이점의 의미는 무엇입니까? 어느 쪽이든, 콜백은 미래가 끝난 후에 불특정 시간에 일어날 것을 보장합니다. 그래서 두 클래스간에 완벽하게 일치하지 않습니까?

답변

3

concurrent.futures.Future은 일반적으로 Executor을 사용할 때 다른 스레드와 프로세스간에 결과를 공유하는 방법을 제공합니다.

asyncio.Future은 실제로는 하나의 프로세스/스레드에서 비동기로 실행되는 특수한 종류의 함수 인 coroutines에 대해 동일한 작업을 해결합니다. 현재의 컨텍스트에서 "비동기 적으로"는 이벤트 루프가이 코 루틴의 흐름을 실행하는 코드를 관리한다는 것을 의미합니다. 하나의 코 루틴 내부에서 실행을 일시 중단하고 다른 코 루틴을 실행하고 나중에 첫 번째 실행으로 돌아갑니다. 스레드/프로세스와 코 루틴과 코드에서 동시성의 개념이 유사하기 때문에

이러한 개체 (같은 많은 다른 threading/asyncio 객체는 Lock, Event, Semaphore 등)과 유사.

개체가 다른 주된 이유는 다음과 같습니다. asyncio 나중에 많이 작성한 후 threadingconcurrent.futures입니다. concurrent.futures.Future을 클래스 API를 위반하지 않고 asyncio과 작동하도록 변경하는 것은 불가능합니다.

두 클래스 모두 "이상적인 세계"에 있어야합니까? 이것은 아마도 논란의 여지가있는 문제이지만, 많은 단점이 있습니다. asynciothreading은 처음에는 유사하지만, 내부 구현이나 asyncio/non-asyncio 코드 작성 방법을 포함하여 여러 가지면에서 매우 다릅니다 (async/await 키워드).

클래스가 다르다는 것이 가장 좋은 방법이라고 생각합니다. 처음에는 유사성이 이상하게 보일지라도 동시성의 성격에 따라 분명히 구분됩니다.

4

차이의 핵심 원인은 스레드 (및 프로세스)가 블록을 처리하는 방법과 차단하는 이벤트를 coroutine이 처리하는 방법입니다. 스레딩에서 현재 스레드는 조건이 해결되고 스레드가 앞으로 나아갈 때까지 일시 중단됩니다. 예를 들어 미래의 경우 미래의 결과를 요청하면 그 결과가 사용 가능할 때까지 현재 스레드를 일시 중단하는 것이 좋습니다.

그러나 이벤트 루프의 동시성 모델은 코드를 일시 중단하는 것이 아니라 이벤트 루프로 돌아가서 준비가되면 다시 호출되도록합니다. 따라서 결과가 준비되지 않은 asyncio 미래의 결과를 요청하는 것은 오류입니다.

당신은 asyncio 미래가 단지 기다릴 수 있다고 생각할 것입니다. 그리고 비효율적 일 것입니다, 당신의 코 루틴이 차단하는 것이 정말 좋지 않을까요? 코 루틴 블록을 가지고 있으면 미래가 결코 완료되지 않을 가능성이 높습니다. 결과를 요청하는 코드를 실행하는 이벤트 루프와 관련된 일부 코드로 미래의 결과가 설정 될 가능성이 큽니다. 해당 이벤트 루프를 실행하는 스레드가 차단되면 이벤트 루프와 연관된 코드가 실행되지 않습니다. 따라서 결과를 차단하면 교착 상태가 발생하고 결과가 생성되지 않습니다.

그래, 인터페이스의 차이는이 고유 한 차이 때문입니다. 예를 들어, concurrent.futures 웨이터 추상화에 asyncio future를 사용하지 않으려는 경우 이벤트 루프 스레드를 다시 차단하므로 다시 사용하지 않아도됩니다.

차이점은 add_done_callbacks이므로 콜백이 이벤트 루프에서 실행됨을 보장합니다. 이는 이벤트 루프의 스레드 로컬 데이터를 가져 오기 때문에 바람직합니다. 또한 많은 코 루틴 코드는 동일한 이벤트 루프의 다른 코드와 동시에 실행되지 않는다고 가정합니다. 즉, coroutine은 동일한 이벤트 루프의 두 coroutine이 동시에 실행되지 않는다는 가정하에 쓰레드 안전합니다. 이벤트 루프에서 콜백을 실행하면 많은 스레드 안전 문제가 발생하지 않으며 올바른 코드를 쉽게 작성할 수 있습니다.