Program Tip

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

programtip 2020. 10. 7. 08:08
반응형

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의 하위 클래스이기 때문에를 포함 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으로 중복됩니다.

Similar question What's the difference between loop.create_task, asyncio.async/ensure_future and Task?


Note: Only valid for Python 3.7 (for Python 3.5 refer to the earlier answer).

From the official docs:

asyncio.create_task (added in Python 3.7) is the preferable way for spawning new tasks instead of ensure_future().


Detail:

So now, in Python 3.7 onwards, there are 2 top-level wrapper function (similar but different):

Well, utlimately both of these wrapper functions will help you call BaseEventLoop.create_task. The only difference is ensure_future accept any awaitable object and help you convert it into a Future. And also you can provide your own event_loop parameter in ensure_future. And depending if you need those capability or not, you can simply choose which wrapper to use.


for your example, all the three types execute asynchronously. the only difference is that, in the third example, you pre-generated all 10 coroutines, and submitted to the loop together. so only the last one gives output randomly.

참고URL : https://stackoverflow.com/questions/36342899/asyncio-ensure-future-vs-baseeventloop-create-task-vs-simple-coroutine

반응형