programing

Python 3.5에서 코루틴과 미래/작업의 차이점은 무엇입니까?

goodsources 2023. 5. 6. 14:57
반응형

Python 3.5에서 코루틴과 미래/작업의 차이점은 무엇입니까?

더미 함수가 있다고 가정합니다.

async def foo(arg):
    result = await some_remote_call(arg)
    return result.upper()

다음의 차이점은 무엇입니까?

import asyncio    

coros = []
for i in range(5):
    coros.append(foo(i))

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(coros))

그리고:

import asyncio

futures = []
for i in range(5):
    futures.append(asyncio.ensure_future(foo(i)))

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(futures))

참고: 예제는 결과를 반환하지만, 이것은 질문의 초점이 아닙니다.반환 가치가 중요한 경우 사용gather()wait().

수익률과 상관없이, 저는 명확한 정보를 찾고 있습니다.ensure_future().wait(coros)그리고.wait(futures)둘 다 코루틴을 운영하기 때문에, 코루틴은 언제 그리고 왜 포장되어야 합니까.ensure_future?

3의 Python 3.5를 하여 많은 방법입니까?async?

추가 크레딧을 위해서, 제가 전화를 일괄 처리하고 싶으면 어떻게 합니까?예를 들어, 전화를 해야 합니다.some_remote_call(...)1000번이지만 1000번의 동시 연결로 웹 서버/데이터베이스/등을 크래시하고 싶지 않습니다.은 스레드나 할 수 , 스드또는프풀실수있사, 위있까습니방이법한만지이를로 할 수 있는 이 있습니까?asyncio?

2020년 업데이트(파이썬 3.7+):이 스니펫을 사용하지 마십시오.대신 다음을 사용합니다.

import asyncio

async def do_something_async():
    tasks = []
    for i in range(5):
        tasks.append(asyncio.create_task(foo(i)))
    await asyncio.gather(*tasks)

def do_something():
    asyncio.run(do_something_async)

또한 비동기식에 대한 강력한 타사 대안인 Trio를 사용하는 것도 고려해 보십시오.

코루틴은 값을 산출하고 외부로부터 값을 수용할 수 있는 생성기 함수입니다.코루틴을 사용하면 함수 실행을 일시 중지하고 나중에 다시 시작할 수 있습니다.네트워크 작업의 경우 응답을 기다리는 동안 함수 실행을 일시 중지하는 것이 좋습니다.다른 기능을 실행하는 데 시간을 사용할 수 있습니다.

는 미는마치와 .PromiseJavascript 입니다.그것은 미래에 구체화될 가치의 자리 표시자와 같습니다.위에서 언급한 경우, 네트워크 I/O에서 대기하는 동안 함수는 컨테이너를 제공할 수 있습니다. 즉, 작업이 완료되면 컨테이너에 값을 채울 것이라는 약속입니다.우리는 미래의 물체를 붙잡고 그것이 실현되면, 우리는 실제 결과를 얻기 위해 그것에 대한 방법을 호출할 수 있습니다.

직접 답변:필요없습니다ensure_future결과가 필요 없는 경우.결과가 필요하거나 발생한 예외를 검색하는 경우 유용합니다.

추가 학점:나는 선택하고 통과할 것입니다.Executor최대 작업자 수를 제어하는 인스턴스입니다.

설명 및 샘플 코드

첫 번째 예제에서는 코루틴을 사용하고 있습니다.wait함수는 코루틴의 다발을 가지고 그것들을 함께 결합합니다.그렇게wait()모든 코루틴이 소진되면 종료됩니다(모든 값을 반환함/반환함).

loop = get_event_loop() # 
loop.run_until_complete(wait(coros))

run_until_complete메소드는 실행이 완료될 때까지 루프가 활성 상태인지 확인합니다.이 경우 비동기 실행 결과를 얻을 수 없습니다.

에서는 두번예는다사있습고니다용하음을에서째▁the있을 사용하고 있습니다.ensure_future하는 Task Future코루틴은 당신이 호출할 때 메인 이벤트 루프에서 실행되도록 예약되어 있습니다.ensure_future반환된 미래/작업 개체에는 아직 값이 없지만 시간이 지남에 따라 네트워크 작업이 완료되면 미래 개체에 작업 결과가 저장됩니다.

from asyncio import ensure_future

futures = []
for i in range(5):
    futures.append(ensure_future(foo(i)))

loop = get_event_loop()
loop.run_until_complete(wait(futures))

그래서 이 예에서 우리는 코루틴을 사용하는 대신 미래를 사용하는 것을 제외하고는 같은 일을 하고 있습니다.

비동기/코루틴/미래를 사용하는 방법의 예를 살펴보겠습니다.

import asyncio


async def slow_operation():
    await asyncio.sleep(1)
    return 'Future is done!'


def got_result(future):
    print(future.result())

    # We have result, so let's stop
    loop.stop()


loop = asyncio.get_event_loop()
task = loop.create_task(slow_operation())
task.add_done_callback(got_result)

# We run forever
loop.run_forever()

여기서는 다음을 사용했습니다.create_task에 있는 loop물건. ensure_future주 이벤트 루프에서 작업을 예약합니다.이 방법을 사용하면 선택한 루프에서 코루틴을 예약할 수 있습니다.

또한 다음을 사용하여 콜백을 추가하는 개념도 볼 수 있습니다.add_done_callback메서드가 작업 개체에 있습니다.

A Task이라done코루틴이 값을 반환하거나, 예외를 제기하거나, 취소되는 경우.이러한 인시던트를 확인하는 방법이 있습니다.

다음과 같은 주제에 대한 블로그 게시물을 작성했습니다.

물론 자세한 내용은 공식 매뉴얼 https://docs.python.org/3/library/asyncio.html 에서 확인하실 수 있습니다.

TL;DR

  • 함수 (코루틴함호출수((()async def 실행하지 않습니다.생성기 함수가 생성기 개체를 반환하는 것과 같은 코루틴 개체를 반환합니다.
  • await코루틴에서 값을 검색합니다. 즉, 코루틴을 "검색"합니다.
  • eusure_future/create_task코루틴을 래핑하고 다음 반복 시 이벤트 루프에서 실행되도록 예약하지만 종료될 때까지 기다리지 않습니다. 데몬 스레드와 같습니다.
  • 코루틴 또는 코루틴을 포장하는 작업을 대기하면 항상 코루틴에서 반환된 결과를 검색할 수 있습니다. 차이점은 실행 순서입니다.

몇 가지 코드 예제

먼저 몇 가지 조건을 삭제합니다.

  • 함수,즉 당신이 루틴함수하, 는이것신당코 하는 .async defs;
  • 코루틴 객체, 코루틴 함수를 "호출"했을 때 얻을 수 있는 것;
  • 작업, 이벤트 루프에서 실행할 코루틴 개체를 감싸는 개체입니다.
  • 수 있는,이 할 수 있는 것, 기다릴 수 있는 것.await예를 들어 작업, 미래 또는 일반 코루틴 객체.

어용coroutine상황에 따라 코루틴 함수와 코루틴 객체가 모두 될 수 있지만 차이를 구분하기에 충분히 쉬울 것입니다.

1, 제1조await에.

는 두 개의. 두 개 의 코 루 만 들 을 고 틴 만 들 고 , ▁we두 ▁two 을await하나, 그리고 용도create_task다른 하나를 실행합니다.

import asyncio
import time

# coroutine function
async def log_time(word):
    print(f'{time.time()} - {word}')

async def main():
    coro = log_time('plain await')
    task = asyncio.create_task(log_time('create_task'))  # <- runs in next iteration
    await coro  # <-- run directly
    await task

if __name__ == "__main__":
    asyncio.run(main())

다음과 같은 결과를 얻을 수 있습니다. 예상대로 플레인 코루틴이 먼저 실행되었습니다.

1539486251.7055213 - plain await
1539486251.7055705 - create_task

ㅠㅠcoro되었고, 실었며으되행직접,며으▁was▁directly▁executed,task다음 반복에서 실행되었습니다.

사례 2, 이벤트 루프에 대한 제어 권한 부여

전로화에 으로써.asyncio.sleep(1)컨트롤이 루프로 반환되면 다른 결과가 표시됩니다.

async def main():
    coro = log_time('plain await')
    task = asyncio.create_task(log_time('create_task'))  # <- runs in next iteration
    await asyncio.sleep(1)  # <- loop got control, and runs task
    await coro  # <-- run directly
    await task

다음과 같은 결과가 표시됩니다. 실행 순서가 반대로 적용됩니다.

1539486378.5244057 - create_task
1539486379.5252144 - plain await

를 부를 때asyncio.sleep(1)은 이벤트 루프로 "" "" " " " " " " " 를 합니다.task에해의창에 의해 되었습니다.create_task

했지만, 비록우코기루먼능을호저, .await방금 코루틴을 만들었습니다. 자동으로 시작되지 않습니다.그리고 나서, 우리는 새로운 코루틴을 만들고 그것을 포장합니다.create_task 러불,creat_task에서는 코루틴을 래핑할 뿐만 아니라 다음 반복 시 실행할 작업을 예약합니다. 결과, 결적으로과,create_task 앞에 됩니다.plain await.

여기서 마법은 루프에 제어권을 다시 주는 것입니다. 사용할 수 있습니다.asyncio.sleep(0)동일한 결과를 얻기 위해.

모든 차이가 있은 후에도 같은 것이 있습니다. 코루틴이나 코루틴을 포장하는 작업, 즉 대기 중인 작업을 기다리면 언제든지 결과를 검색할 수 있습니다.

후드 아래

asyncio.create_task 출들asyncio.tasks.Task()전화가 올 것입니다.loop.call_soon.그리고.loop.call_soon을 작을수니다합에 넣습니다.loop._ready루프가 반복될 때마다 모든 콜백을 확인합니다.loop._ready그리고 그것을 운영합니다.

asyncio.wait,asyncio.ensure_future그리고.asyncio.gather실제로 전화를 걸었습니다loop.create_task직간접적으로

문서에도 참고:

콜백은 등록된 순서대로 호출됩니다.각 콜백은 정확히 한 번 호출됩니다.

https://github.com/python/asyncio/blob/master/asyncio/tasks.py#L346, 에 연결된 빈센트의 논평은 다음을 보여줍니다.wait()을 코틴을감다싼으로 .ensure_future()당신을 위해!

다시 말해서, 우리는 미래가 필요하고, 코루틴은 조용히 그것들로 바뀔 것입니다.

코루틴/미래 배치 방법에 대한 확실한 설명이 나오면 이 답변을 업데이트하겠습니다.

BDFL에서 [2013]

임무들

  • 미래에 포장된 코루틴입니다.
  • 클래스 작업은 클래스 미래의 하위 클래스입니다.
  • 그래서 wait에서도 작동합니다!

  • 맨 코루틴과 어떻게 다릅니까?
  • 기다리지 않고 진행할 수 있습니다.
    • 당신이 다른 것을 기다리는 한, 즉.
      • 기다리다[기다리다]

에 두고, 이을염두두고에것,고,ensure_future사용자가 작업을 기다리는지 여부에 관계없이 미래의 결과가 계산되므로 작업을 생성하기 위한 이름으로 사용할 수 있습니다.이렇게 하면 다른 작업을 기다리는 동안 이벤트 루프가 작업을 완료할 수 있습니다.Python 3.7에서는create_task미래를 보장하는 것이 선호되는 방법입니다.

참고: Guido의 슬라이드에서 "수익률"을 현대성을 위해 "기다림"으로 변경했습니다.

이미 매우 유용한 답변이 몇 개 있지만 모든 뉘앙스를 다루지는 않습니다.특히, 받아들여진 대답은 더 이상 정확하지 않습니다.

사용하면 안 됩니다.wait코루틴 포함 - 새 버전의 라이브러리와 호환됩니다.

설명서:

버전 3.8 이후에는 사용되지 않습니다. 버전 3.11에서는 제거될 예정입니다. 코루틴 개체를 대기()에 직접 전달하는 것은 더 이상 사용되지 않습니다.

그리고 설명서의 또 다른 설명은 깊은 이해에 유용할 수 있습니다.『 』의 결과wait 먼저 코루틴을 미래로 포장해야 .create_task이 (에)ensure_future).

wait()는 자동으로 작업으로 코루틴을 예약하고 나중에 암묵적으로 생성된 작업 개체를 (완료, 보류 중) 세트로 반환합니다.따라서 다음 코드가 예상대로 작동하지 않습니다.

async def foo():
    return 42

coro = foo() 
done, pending = await asyncio.wait({coro})

if coro in done:
    # This branch will never be run! 

위의 스니펫을 수정하는 방법은 다음과 같습니다.

    return 42

task = asyncio.create_task(foo()) 
done, pending = await asyncio.wait({task})

if task in done:
    # Everything will work as expected now. 

언급URL : https://stackoverflow.com/questions/34753401/difference-between-coroutine-and-future-task-in-python-3-5

반응형