[Python] Asyncio_04

atesi·2022년 9월 20일
0

asyncio

목록 보기
4/7

Running async programs

Python 3.7에 asyncio.run()이 도입되고 Python 3.10에서 많은 asyncio 함수에서 loop 매개변수가 제거됨에 따라 비동기 라이브러리를 개발하지 않는 한 이벤트 루프를 관리하는 일은 거의 일어나지 않는다. 이벤트 루프 객체는 여전히 존재하며 액세스할 수 있다. 만약 파이썬 3.7 버전 이상에서 작업하고 있다면 asyncio.run()에 대해 감사하면 된다.

asyncio.run(coro)coro를 실행시키고 결과를 반환할 것이다. 매번 새로운 이벤트 루프를 실행시키며 그 이벤트 루프를 실행 중일 때는 호출 될 수 없다. 이것은 비동기 코드를 실행하는 몇 가지 명백한 방법으로 이어진다.

첫 번째는 모든 것을 비동기 코루틴에 넣고 매우 간단한 엔트리 함수를 가지게 하는 것이다.

import asyncio

async def get_data_from_io():
    ...

async def process_data(data):
    ...

async def main():
    while true:
        data = await get_data_from_io()
        await process_data(data)

asyncio.run(main())

두 번째는 각 코루틴 호출을 별도의 run 명령으로 래핑하는 것이다. 이렇게 하면 asyncio의 모든 이점이 손실된다. 그럼에도 이렇게 해야 하는 스크립트가 있을 수도 있다.

import asyncio

async def get_data_from_io():
    ...

async def process_data(data):
    ...

def main():
    while true:
        data = asyncio.run(get_data_from_io())
        asyncio.run(process_data(data))

main()

How to yield control

다른 작업이 실행될 수 있도록 이벤트 루프에 제어를 양보하는 간단한 명령은 없다. asyncio 프로그램의 대부분의 경우 이것은 명시적으로 수행하려는 것이 아니라, 특정 유형의 IO를 처리하는 일부 기본 라이브러리에서 반환되는 future를 기다릴 때 제어가 자동으로 생성되도록 허용하는 것을 선호한다.

그러나 경우에 따라 특히 테스트 및 디버깅 중에 매우 유용하다. 결과적으로 필요에 따라 이를 수행하는 인식된 관용구가 있다.

await asyncio.sleep(0)

위의 코드는 현재 작업을 일시중지시키고 다른 일을 실행할 수 있다. 이 함수는 시간(초)단위의 단일 매개변수를 사용하고 아직 완료로 표시되지 않았지만 지정된 시간(초)가 경과했을 때 표시될 미래를 반환한다.

0초로 지정하면 다른 태스크가 보류 중인 경우 현재 작업을 중단하도록 작동하지만 그렇지 않으면 절전 시간이 0이므로 아무 작업도 수행하지 않는다.

asyncio.sleep을 0이 아닌 매개변수와 사용할 경우 시간(초)가 경과했을 때 미래가 완료된다고 해서 작업이 항상 그 시간에 다시 깨어나는 것은 아니다. 실제로 이벤트 루프에서 실행 중인 다른 작업이 없을 때만 깨울 수 있기 때문에 그 시간 이후에는 언제든지 다시 깨울 수 있다.

Summary

  • 항상 비동기 코드 내에서만 await, async with 그리고 async for를 사용할 수 있다.
  • 비동기 코드는 async def(또는 다음 기사에서 설명하는 다른 위치)가 포함되어야 하고 선언은 def가 허용되는 곳이면 어디에나 배치할 수 있다.
  • await를 호출할 때는 반드시 다음 중 하나를 따라야 한다.
    • async def를 사용하여 정의된 코루틴 함수의 반환 값인 coroutine 객체
      • 코루틴 코드는 awaited 또는 작업이 wrapped된 경우에만 실행될 것이다.
    • 완료되었을 수 있는 다른 위치에서 진행 중인 프로세스를 나타내는 future 객체
      • future를 기다리는 것은 코드를 실행할 수 없지만 다른 프로세스가 완료될 때까지 현재 작업을 일시정지 할수 있다.
    • 매직메소드 __await__를 구현하는 객체
  • 코루틴을 태스크에 랩핑하여 실행하고 결과를 모니터링하는 데 사용할 수 있는 future을 리턴할 수 있다.

Making an actual program

이것으로 비동기 코드 작성을 위한 기본 구문에 대한 설명을 마칩니다. 이것만으로도 이미 여러 작업을 인스턴스 화하고 교체할 수 있는 좋은 비동기 프로그램을 만들 수 있습니다. 다음 예제는 이 게시물에 포함된 것만 사용하여 작동하는 Python 프로그램입니다.

import asyncio

async def counter(name: str):
    for i in range(0, 100):
        print(f"{name}: {i!s}")
        await asyncio.sleep(0)

async def main():
    tasks = []
    for n in range(0, 4):
        tasks.append(asyncio.create_task(counter(f"task{n}")))

    while True:
        tasks = [t for t in tasks if not t.done()]
        if len(tasks) == 0:
            return

        await tasks[0]

asyncio.run(main())

이 프로그램은 0에서 99까지의 숫자를 인쇄하는 4개의 작업을 실행하고 각 작업을 인쇄한 후 다른 작업이 인계받을 수 있도록 제어합니다. asyncio가 여러 작업을 인터리브 처리할 수 있음을 깔끔하게 보여줍니다.

profile
Action!

0개의 댓글