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()
코 루틴 또는 aFuture
(후자는Task
의 하위 클래스이기 때문에 a가 포함됨Future
)가 될 수 있고,Future
(아마 유일한 것에 대해) 정의 된 메서드를 호출 할 수 있기를 원하는 경우입니다. 유용한 예cancel()
). 이미 aFuture
(또는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 이후에는 두 개의 최상위 래퍼 함수가 있습니다 (유사하지만 다름).
asyncio.create_task
: 단순히event_loop.create_task(coro)
직접 호출 합니다. ( 소스 코드 참조 )ensure_future
이는 또한 전화event_loop.create_task(coro)
가 코 루틴입니다 그렇지 않으면이 될 반환 형식을 보장하는 것입니다 경우 asyncio.Future . ( 소스 코드 참조 ). 어쨌든,Task
여전히Future
클래스 상속 ( ref ) 때문입니다.
음,이 두 래퍼 함수는 모두 BaseEventLoop.create_task
. 유일한 차이점은 ensure_future
모든 awaitable
객체를 받아들이고 이를 Future로 변환하는 데 도움이되는 것입니다. 또한 event_loop
에서 고유 한 매개 변수를 제공 할 수 있습니다 ensure_future
. 이러한 기능이 필요한지 여부에 따라 사용할 래퍼를 선택하기 만하면됩니다.
답변
예를 들어 세 가지 유형 모두 비동기 적으로 실행됩니다. 유일한 차이점은 세 번째 예제에서 10 개의 코 루틴을 모두 미리 생성하고 함께 루프에 제출했다는 것입니다. 그래서 마지막 하나만 무작위로 출력을 제공합니다.
답변
