[python] asyncio.ensure_future 대 BaseEventLoop.create_task 대 단순 코 루틴?

asyncio에 대한 몇 가지 기본 Python 3.5 자습서가 다양한 방식으로 동일한 작업을 수행하는 것을 보았습니다. 이 코드에서 :

import asyncio

async def doit(i):
    print("Start %d" % i)
    await asyncio.sleep(3)
    print("End %d" % i)
    return i

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    #futures = [asyncio.ensure_future(doit(i), loop=loop) for i in range(10)]
    #futures = [loop.create_task(doit(i)) for i in range(10)]
    futures = [doit(i) for i in range(10)]
    result = loop.run_until_complete(asyncio.gather(*futures))
    print(result)

futures변수 를 정의하는 위의 세 가지 변형 모두 동일한 결과를 얻습니다. 내가 볼 수있는 유일한 차이점은 세 번째 변형의 경우 실행 순서가 잘못되었다는 것입니다 (대부분의 경우 중요하지 않음). 다른 차이점이 있습니까? 가장 단순한 변형 (코 루틴의 일반 목록)을 사용할 수없는 경우가 있습니까?



답변

실제 정보 :

이 목적을 위해 Python 3.7부터 asyncio.create_task(coro)고급 기능 이 추가되었습니다 .

대신 coroutimes에서 작업을 만드는 다른 방법을 사용해야합니다. 그러나 임의의 awaitable에서 작업을 생성해야하는 경우 asyncio.ensure_future(obj).


이전 정보 :

ensure_future vs create_task

ensure_future에서 만드는 방법 Task입니다 coroutine. 인수에 따라 다른 방식으로 작업을 생성합니다 ( create_task코 루틴 및 미래형 객체 에 대한 사용 포함 ).

create_task의 추상 방법입니다 AbstractEventLoop. 다른 이벤트 루프는이 기능을 다른 방식으로 구현할 수 있습니다.

ensure_future작업을 생성하는 데 사용해야 합니다. create_task자체 이벤트 루프 유형을 구현하려는 경우에만 필요 합니다.

업데이트 :

@ bj0 은이 주제에 대한 Guido의 답변 을 지적했습니다 .

요점은 ensure_future()코 루틴 또는 a Future(후자는 Task의 하위 클래스이기 때문에 a가 포함됨 Future)가 될 수 있고, Future(아마 유일한 것에 대해) 정의 된 메서드를 호출 할 수 있기를 원하는 경우입니다. 유용한 예 cancel()). 이미 a Future(또는 Task) 이면 아무 작업도 수행하지 않습니다. 그것은 코 루틴 인 경우는 A의 그것 Task.

코 루틴이 있다는 것을 알고 있고이를 예약하려는 경우 사용할 올바른 API는 create_task(). 호출해야하는 유일한 시간 ensure_future()은 코 루틴 또는 a를 허용하는 API (대부분의 asyncio 자체 API와 같이)를 제공 Future하고 Future.

이후 :

결국 나는 그것이 ensure_future()거의 필요하지 않은 기능에 대한 적절하게 모호한 이름 이라고 여전히 믿습니다 . 코 루틴에서 작업을 생성 할 때 적절한 이름의
loop.create_task(). 아마도 그것에 대한 별칭이 있어야
asyncio.create_task()할까요?

놀랍습니다. ensure_future함께 사용 하는 주된 동기 는 루프의 구성원과 비교하여 더 높은 수준의 기능이라는 것이 었습니다 create_task(토론 에는 추가 asyncio.spawn또는 같은 아이디어 가 포함되어 있습니다asyncio.create_task ).

또한 Awaitable코 루틴 만 처리 할 수있는 것이 아니라 모든 것을 처리 할 수있는 범용 함수를 사용하는 것이 매우 편리하다고 생각합니다 .

그러나 Guido의 대답은 분명합니다. “코 루틴에서 작업을 만들 때는 적절한 이름을 사용해야합니다. loop.create_task()

코 루틴을 작업에 래핑해야하는 경우

코 루틴을 태스크에 래핑-이 코 루틴을 “백그라운드에서”시작하는 방법입니다. 예를 들면 다음과 같습니다.

import asyncio


async def msg(text):
    await asyncio.sleep(0.1)
    print(text)


async def long_operation():
    print('long_operation started')
    await asyncio.sleep(3)
    print('long_operation finished')


async def main():
    await msg('first')

    # Now you want to start long_operation, but you don't want to wait it finised:
    # long_operation should be started, but second msg should be printed immediately.
    # Create task to do so:
    task = asyncio.ensure_future(long_operation())

    await msg('second')

    # Now, when you want, you can await task finised:
    await task


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

산출:

first
long_operation started
second
long_operation finished

차이를 느끼기 위해 asyncio.ensure_future(long_operation())로 대체 할 수 있습니다 await long_operation().


답변

create_task()

  • 코 루틴을 받아들이고,
  • Task를 반환합니다.
  • 루프의 컨텍스트에서 호출됩니다.

ensure_future()

  • Futures, 코 루틴, awaitable 객체,
  • Task (또는 Future가 전달 된 경우 Future)를 반환합니다.
  • 주어진 arg가 코 루틴이면 create_task,
  • 루프 객체를 전달할 수 있습니다.

보시다시피 create_task가 더 구체적입니다.


async create_task 또는 ensure_future없이 기능

간단한 호출 async함수는 코 루틴을 반환합니다.

>>> async def doit(i):
...     await asyncio.sleep(3)
...     return i
>>> doit(4)
<coroutine object doit at 0x7f91e8e80ba0>

그리고 gather내부적으로는 ensure_future인수가 미래라는 것을 ( ) 보장하기 때문에 명시 적으로ensure_future 으로 중복됩니다.

비슷한 질문 loop.create_task, asyncio.async / ensure_future 및 Task의 차이점은 무엇입니까?


답변

참고 : Python 3.7 에서만 유효합니다 (Python 3.5의 경우 이전 답변 참조 ).

공식 문서에서 :

asyncio.create_task(Python 3.7에 추가됨) ensure_future().


세부 묘사:

이제 Python 3.7 이후에는 두 개의 최상위 래퍼 함수가 있습니다 (유사하지만 다름).

음,이 두 래퍼 함수는 모두 BaseEventLoop.create_task. 유일한 차이점은 ensure_future모든 awaitable객체를 받아들이고 이를 Future로 변환하는 데 도움이되는 것입니다. 또한 event_loop에서 고유 한 매개 변수를 제공 할 수 있습니다 ensure_future. 이러한 기능이 필요한지 여부에 따라 사용할 래퍼를 선택하기 만하면됩니다.


답변

예를 들어 세 가지 유형 모두 비동기 적으로 실행됩니다. 유일한 차이점은 세 번째 예제에서 10 개의 코 루틴을 모두 미리 생성하고 함께 루프에 제출했다는 것입니다. 그래서 마지막 하나만 무작위로 출력을 제공합니다.


답변