Python

코루틴과 태스크

이 절에서는 코루틴과 태스크로 작업하기 위한 고급 asyncio API에 관해 설명합니다.

코루틴

소스 코드: Lib/asyncio/coroutines.py


async/await 문법으로 선언된 코루틴은 asyncio 응용 프로그램을 작성하는 기본 방법입니다. 예를 들어, 다음 코드 조각은 “hello”를 인쇄하고, 1초 동안 기다린 다음, “world”를 인쇄합니다:

>>> import asyncio

>>> async def main():
...     print('hello')
...     await asyncio.sleep(1)
...     print('world')

>>> asyncio.run(main())
hello
world

단지 코루틴을 호출하는 것으로 실행되도록 예약하는 것은 아닙니다:

>>> main()
<coroutine object main at 0x1053bb7c8>

코루틴을 실제로 실행하기 위해, asyncio가 다음과 같은 메커니즘을 제공합니다:

  • 최상위 진입점 “main()” 함수를 실행하는 asyncio.run() 함수 (위의 예를 보세요.)

  • 코루틴을 기다리기. 다음 코드 조각은 1초를 기다린 후 “hello”를 인쇄한 다음 2초를 기다린 후 “world”를 인쇄합니다:

    import asyncio
    import time
    
    async def say_after(delay, what):
        await asyncio.sleep(delay)
        print(what)
    
    async def main():
        print(f"started at {time.strftime('%X')}")
    
        await say_after(1, 'hello')
        await say_after(2, 'world')
    
        print(f"finished at {time.strftime('%X')}")
    
    asyncio.run(main())
    

    예상 출력:

    started at 17:13:52
    hello
    world
    finished at 17:13:55
    
  • 코루틴을 asyncio 태스크로 동시에 실행하는 asyncio.create_task() 함수.

    위의 예를 수정해서 두 개의 say_after 코루틴을 동시에 실행해 봅시다:

    async def main():
        task1 = asyncio.create_task(
            say_after(1, 'hello'))
    
        task2 = asyncio.create_task(
            say_after(2, 'world'))
    
        print(f"started at {time.strftime('%X')}")
    
        # 두 태스크가 모두 완료할 때까지 기다립니다 (2초 정도
        # 걸려야 합니다.)
        await task1
        await task2
    
        print(f"finished at {time.strftime('%X')}")
    

    예상 출력은 이제 코드 조각이 이전보다 1초 빠르게 실행되었음을 보여줍니다:

    started at 17:14:32
    hello
    world
    finished at 17:14:34
    
  • asyncio.TaskGroup 클래스는 create_task() 에 대한 더 현대적인 대안을 제공합니다. 이 API를 사용하면 마지막 예제는 다음과 같이 바뀝니다:

    async def main():
        async with asyncio.TaskGroup() as tg:
            task1 = tg.create_task(
                say_after(1, 'hello'))
    
            task2 = tg.create_task(
                say_after(2, 'world'))
    
            print(f"started at {time.strftime('%X')}")
    
        # 컨텍스트 매니저를 빠져나갈 때 어웨이트는 묵시적입니다.
    
        print(f"finished at {time.strftime('%X')}")
    

    타이밍과 출력은 이전 버전과 동일해야 합니다.

    Added in version 3.11: asyncio.TaskGroup.

어웨이터블

우리는 객체가 await 표현식에서 사용될 수 있을 때 어웨이터블 객체라고 말합니다. 많은 asyncio API는 어웨이터블을 받아들이도록 설계되었습니다.

어웨이터블 객체에는 세 가지 주요 유형이 있습니다: 코루틴, 태스크퓨처.

코루틴

파이썬 코루틴은 어웨이터블이므로 다른 코루틴에서 기다릴 수 있습니다:

import asyncio

async def nested():
    return 42

async def main():
    # 단지 "nested()" 를 호출하면 아무 일도 일어나지 않습니다.
    # 코루틴 객체가 생성되었지만 기다리지 않았습니다.
    # 따라서 *전혀 실행되지 않습니다*.
    nested()  # will raise a "RuntimeWarning".

    # 이제 다른 식으로 해봅시다, 기다립니다:
    print(await nested())  # "42" 를 인쇄합니다.

asyncio.run(main())

중요

이 설명서에서 “코루틴” 이라는 용어는 두 가지 밀접한 관련 개념에 사용될 수 있습니다:

  • 코루틴 함수: async def 함수;

  • 코루틴 객체: 코루틴 함수를 호출하여 반환된 객체.

태스크

태스크는 코루틴을 동시에 예약하는 데 사용됩니다.

코루틴이 asyncio.create_task()와 같은 함수를 사용하여 태스크로 싸일 때 코루틴은 곧 실행되도록 자동으로 예약됩니다:

import asyncio

async def nested():
    return 42

async def main():
    # nested()가 곧 "main()" 과 동시에 실행되도록
    # 예약합니다.
    task = asyncio.create_task(nested())

    # "task" 는 이제 "nested()" 를 취소하는 데 사용하거나,
    # 단순히 완료할 때까지 기다릴 수 있습니다:
    await task

asyncio.run(main())

퓨처

Future는 비동기 연산의 최종 결과를 나타내는 특별한 저수준 어웨이터블 객체입니다.

Future 객체를 기다릴 때, 그것은 코루틴이 Future가 다른 곳에서 해결될 때까지 기다릴 것을 뜻합니다.

콜백 기반 코드를 async/await와 함께 사용하려면 asyncio의 Future 객체가 필요합니다.

일반적으로 응용 프로그램 수준 코드에서 Future 객체를 만들 필요는 없습니다.

때때로 라이브러리와 일부 asyncio API에 의해 노출되는 Future 객체를 기다릴 수 있습니다:

async def main():
    await function_that_returns_a_future_object()

    # 이것도 유효합니다:
    await asyncio.gather(
        function_that_returns_a_future_object(),
        some_python_coroutine()
    )

Future 객체를 반환하는 저수준 함수의 좋은 예는 loop.run_in_executor()입니다.

태스크 생성

소스 코드: Lib/asyncio/tasks.py


asyncio.create_task(coro, *, name=None, context=None, eager_start=None, **kwargs)

coro 코루틴Task로 감싸고 실행을 예약합니다. Task 객체를 반환합니다.

전체 함수 시그니처는 Task 생성자(또는 팩토리)와 거의 동일합니다. 이 함수의 모든 키워드 인자는 해당 인터페이스로 전달됩니다.

선택적인 키워드 전용 context 인자를 사용하면 코루틴 이 실행될 사용자 정의 contextvars.Context 를 지정할 수 있습니다. context 가 제공되지 않으면 현재 컨텍스트의 복사본이 생성됩니다.

선택적 키워드 전용 인자인 eager_start 를 통해 task를 create_task 호출 시 즉시 실행할지, 아니면 나중에 예약할지를 지정할 수 있습니다. eager_start 가 전달되지 않으면 loop.set_task_factory() 에 의해 설정된 모드가 사용됩니다.

get_running_loop()에 의해 반환된 루프에서 태스크가 실행되고, 현재 스레드에 실행 중인 루프가 없으면 RuntimeError가 발생합니다.

참고

asyncio.TaskGroup.create_task() 는 구조적 동시성(structural concurrency)을 활용하는 새로운 대안으로, 강력한 안전 보장을 바탕으로 관련된 태스크 그룹을 기다릴 수 있게 해줍니다.

중요

실행 중에 태스크가 사라지는 것을 방지하려면 이 함수의 결과에 대한 참조를 저장하십시오. 이벤트 루프는 태스크에 대해 약한 참조(weak reference)만 유지합니다. 다른 곳에서 참조되지 않는 태스크는 완료되기 전이라도 언제든지 가비지 컬렉션될 수 있습니다. 신뢰할 수 있는 “fire-and-forget” 백그라운드 태스크를 위해, 다음과 같이 태스크들을 모음으로 묶으십시오:

background_tasks = set()

for i in range(10):
    task = asyncio.create_task(some_coro(param=i))

    # 태스크를 집합에 추가합니다. 이는 강한 참조를 만듭니다.
    background_tasks.add(task)

    # 완료된 태스크에 대한 참조를 영원히 유지하지 않도록 하려면,
    # 각 태스크가 완료 후에 집합에서 자신의 참조를 제거하도록
    # 하십시오:
    task.add_done_callback(background_tasks.discard)

Added in version 3.7.

버전 3.8에서 변경: name 매개 변수가 추가되었습니다.

버전 3.11에서 변경: context 매개 변수가 추가되었습니다.

버전 3.14에서 변경: 모든 kwargs*를 전달하여 *eager_start 매개 변수를 추가했습니다.

태스크 취소

태스크는 쉽고 안전하게 취소될 수 있습니다. 태스크가 취소되면 다음 기회에 해당 태스크에서 asyncio.CancelledError 가 발생합니다.

코루틴이 안정적으로 정리 로직을 수행하려면 try/finally 블록을 사용하는 것이 좋습니다. asyncio.CancelledError 를 명시적으로 잡는 경우, 일반적으로 정리가 완료된 후에 이를 다시 전파해야 합니다. asyncio.CancelledErrorBaseException 을 직접 상속받으므로 대부분의 코드는 이 예외를 인지할 필요가 없습니다.

asyncio.TaskGroupasyncio.timeout() 과 같이 구조적 동시성을 가능하게 하는 asyncio 구성 요소들은 내부적으로 취소(cancellation)를 사용하여 구현되므로, 코루틴이 asyncio.CancelledError 를 묵음 처리하면 제대로 동작하지 않을 수 있습니다. 마찬가지로 사용자 코드는 일반적으로 uncancel 을 호출해서는 안 됩니다. 하지만 asyncio.CancelledError 를 억제하는 것이 정말로 필요한 경우, 취소 상태를 완전히 제거하기 위해 uncancel() 도 호출해야 합니다.

태스크 그룹

태스크 그룹은 태스크 생성 API와 그룹 내의 모든 태스크가 종료될 때까지 기다리는 편리하고 신뢰할 수 있는 방법을 결합합니다.

class asyncio.TaskGroup

태스크 그룹을 보유하는 비동기 컨텍스트 관리자 입니다. 태스크는 create_task() 를 사용하여 그룹에 추가할 수 있습니다. 컨텍스트 관리자가 종료될 때 모든 태스크가 대기(await)됩니다.

Added in version 3.11.

create_task(coro, *, name=None, context=None, eager_start=None, **kwargs)

이 태스크 그룹에 태스크를 생성합니다. 시그니처는 asyncio.create_task() 와 일치합니다. 태스크 그룹이 비활성 상태(예: 아직 진입하지 않음, 이미 종료됨 또는 셧다운 프로세스 중)인 경우, 주어진 coro 를 닫습니다.

버전 3.13에서 변경: 태스크 그룹이 활성화되어 있지 않으면 해당 코루틴을 닫습니다.

버전 3.14에서 변경: 모든 kwargsloop.create_task() 에 전달합니다.

cancel()

태스크 그룹을 취소합니다. 이는 예외 발생 없이 태스크 그룹의 생명 주기를 조기에 종료하는 것으로, 그룹의 목표가 달성되었거나 더 이상 서비스가 필요하지 않을 때 유용합니다.

아직 완료되지 않은 그룹 내의 모든 태스크와 그룹의 부모(본체)에 대해 cancel() 이 호출됩니다. 태스크 그룹 컨텍스트 관리자는 asyncio.CancelledError 를 발생시키지 않고 종료됩니다.

cancel() 이 태스크 그룹에 진입하기 전에 호출되면, 진입 시점에 그룹이 취소됩니다. 이는 한 코드 조각이 다른 코드 조각에 사용하지 않는 asyncio.TaskGroup 인스턴스를 전달하여 그룹 내에서 실행되는 모든 태스크를 취소할 수 있도록 보장하는 패턴에서 유용합니다.

cancel() 은 멱등성이 있으며, 태스크 그룹이 이미 종료된 후에도 호출될 수 있습니다.

cancel() 을 사용하는 몇 가지 방법:

  • 어떤 조건이나 이벤트에 따라 태스크 그룹 본체에서 호출

  • create_task() 를 통해 자식 태스크에 태스크 그룹 인스턴스를 전달하여, 자식 태스크가 조건에 따라 전체 그룹을 취소할 수 있도록 허용

  • 태스크 그룹을 열기 전에 다른 태스크에 태스크 그룹 인스턴스나 바인딩된 cancel() 메서드를 전달하여 원격 취소가 가능하도록 허용

Added in version 3.15.

예:

async def main():
    async with asyncio.TaskGroup() as tg:
        task1 = tg.create_task(some_coro(...))
        task2 = tg.create_task(another_coro(...))
    print(f"Both tasks have completed now: {task1.result()}, {task2.result()}")

async with 문은 그룹 내의 모든 태스크가 완료될 때까지 기다립니다. 대기하는 동안에도 새로운 태스크가 그룹에 추가될 수 있습니다(예를 들어, 코루틴 중 하나에 tg``를 전달하고 해당 코루틴에서 ``tg.create_task()``를 호출). 또한 특정 조건에 따라 ``tg.cancel()``을 사용하여 전체 태스크 그룹의 종료를 요청할 수도 있습니다. 마지막 태스크가 완료되고 ``async with 블록이 종료되면, 더 이상 그룹에 새로운 태스크를 추가할 수 없습니다.

그룹에 속한 태스크 중 하나가 asyncio.CancelledError 이외의 예외로 처음 실패하면, 그룹 내의 나머지 태스크들이 취소됩니다. 그 이후에는 더 이상 그룹에 태스크를 추가할 수 없습니다. 이 시점에서 async with 문의 본체가 여전히 활성 상태인 경우(즉, __aexit__`이 아직 호출되지 않은 경우), ``async with`() 문을 직접 포함하는 태스크도 취소됩니다. 그 결과로 발생하는 asyncio.CancelledError`는 ``await``를 중단시키지만, 이를 포함하는 ``async with` 문 밖으로 전파되지는 않습니다.

모든 태스크가 완료된 후, 만약 어떤 태스크가 asyncio.CancelledError 이외의 예외로 실패했다면, 해당 예외들은 ExceptionGroup 또는 BaseExceptionGroup (적절한 것에 따라 선택; 관련 문서를 참조하십시오)으로 결합되어 발생합니다.

두 가지 기본 예외는 특별하게 처리됩니다: 만약 어떤 태스크가 KeyboardInterrupt 또는 SystemExit 로 실패하면, 태스크 그룹은 여전히 남은 태스크들을 취소하고 대기하지만, 그 후 ExceptionGroup 이나 BaseExceptionGroup 대신 처음 발생한 KeyboardInterrupt 또는 SystemExit 을 다시 발생시킵니다.

async with 문의 본문이 예외와 함께 종료되면(즉, __aexit__() 가 예외 세트와 함께 호출되면), 이를 태스크 중 하나가 실패한 것과 동일하게 처리합니다. 즉, 남은 태스크들이 취소되고 대기하며, 취소가 아닌 예외들은 예외 그룹으로 묶여 발생합니다. __aexit__() 로 전달된 예외도 asyncio.CancelledError 가 아닌 경우 예외 그룹에 포함됩니다. 이전 단락과 마찬가지로 KeyboardInterruptSystemExit 에 대해서도 동일한 특별 케이스가 적용됩니다.

태스크 그룹은 자신의 __aexit__() 를 “깨우기” 위해 사용하는 내부 취소와 다른 당사자가 실행 중인 태스크에 대해 요청한 취소 요청을 혼동하지 않도록 주의합니다. 특히, 하나의 태스크 그룹이 다른 태스크 그룹 안에 문법적으로 중첩되어 있고 두 그룹 모두 자식 태스크 중 하나에서 동시에 예외를 경험하는 경우, 내부 태스크 그룹이 먼저 자신의 예외를 처리하고, 그 후 외부 태스크 그룹이 또 다른 취소를 받아 자신의 예외를 처리합니다.

태스크 그룹이 외부에서 취소되면서 동시에 ExceptionGroup 을 발생시켜야 하는 경우, 부모 태스크의 cancel() 메서드를 호출합니다. 이는 다음 await 시점에 asyncio.CancelledError 가 발생하도록 보장하여 취소가 누락되지 않게 합니다.

태스크 그룹은 asyncio.Task.cancelling() 에서 보고되는 취소 횟수를 유지합니다.

버전 3.13에서 변경: 동시 내부 및 외부 취소에 대한 처리 방식 개선 및 취소 횟수의 정확한 보존.

잠자기

async asyncio.sleep(delay, result=None)

delay 초 동안 블록합니다.

result가 제공되면, 코루틴이 완료될 때 호출자에게 반환됩니다.

sleep()은 항상 현재 태스크를 일시 중단해서 다른 태스크를 실행할 수 있도록 합니다.

지연 시간(delay)을 0으로 설정하면 다른 태스크가 실행될 수 있는 최적화된 경로를 제공합니다. 이는 긴 시간이 소요되는 함수에서 함수 호출 전체 기간 동안 이벤트 루프가 차단되는 것을 방지하기 위해 사용할 수 있습니다.

5초 동안 현재 날짜를 매초 표시하는 코루틴의 예:

import asyncio
import datetime as dt

async def display_date():
    loop = asyncio.get_running_loop()
    end_time = loop.time() + 5.0
    while True:
        print(dt.datetime.now())
        if (loop.time() + 1.0) >= end_time:
            break
        await asyncio.sleep(1)

asyncio.run(display_date())

버전 3.10에서 변경: loop 매개 변수를 제거했습니다.

버전 3.13에서 변경: delaynan 인 경우 ValueError 를 발생시킵니다.

태스크 동시 실행

awaitable asyncio.gather(*aws, return_exceptions=False)

aws 시퀀스에 있는 어웨이터블 객체동시에 실행합니다.

aws에 있는 어웨이터블이 코루틴이면 자동으로 태스크로 예약됩니다.

모든 어웨이터블이 성공적으로 완료되면, 결과는 반환된 값들이 합쳐진 리스트입니다. 결괏값의 순서는 aws에 있는 어웨이터블의 순서와 일치합니다.

return_exceptionsFalse(기본값)면, 첫 번째 발생한 예외가 gather()를 기다리는 태스크로 즉시 전파됩니다. aws 시퀀스의 다른 어웨이터블은 취소되지 않고 계속 실행됩니다.

return_exceptionsTrue면, 예외는 성공적인 결과처럼 처리되고, 결과 리스트에 집계됩니다.

gather()취소되면, 모든 제출된 (아직 완료되지 않은) 어웨이터블도 취소됩니다.

aws 시퀀스의 Task나 Future가 취소되면, 그것이 CancelledError를 일으킨 것처럼 처리됩니다 – 이때 gather() 호출은 취소되지 않습니다. 이것은 제출된 태스크/퓨처 하나를 취소하는 것이 다른 태스크/퓨처를 취소하게 되는 것을 막기 위한 것입니다.

참고

태스크를 동시에 생성 및 실행하고 완료를 기다리는 새로운 대안은 asyncio.TaskGroup 입니다. TaskGroup 은 서브태스크 중첩을 예약할 때 gather 보다 더 강력한 안전 보장을 제공합니다. 즉, 태스크(또는 서브태스크인, 태스크에 의해 예약된 태스크)가 예외를 발생시키면, gather 와 달리 TaskGroup 은 남은 예정 태스크들을 취소합니다.

예:

import asyncio

async def factorial(name, number):
    f = 1
    for i in range(2, number + 1):
        print(f"Task {name}: Compute factorial({number}), currently i={i}...")
        await asyncio.sleep(1)
        f *= i
    print(f"Task {name}: factorial({number}) = {f}")
    return f

async def main():
    # 3개의 호출을 *동시에* 예약합니다:
    L = await asyncio.gather(
        factorial("A", 2),
        factorial("B", 3),
        factorial("C", 4),
    )
    print(L)

asyncio.run(main())

# 예상 출력:
#
#     Task A: Compute factorial(2), currently i=2...
#     Task B: Compute factorial(3), currently i=2...
#     Task C: Compute factorial(4), currently i=2...
#     Task A: factorial(2) = 2
#     Task B: Compute factorial(3), currently i=3...
#     Task C: Compute factorial(4), currently i=3...
#     Task B: factorial(3) = 6
#     Task C: Compute factorial(4), currently i=4...
#     Task C: factorial(4) = 24
#     [2, 6, 24]

참고

return_exceptions가 거짓이면, 완료로 표시된 후 gather()를 취소하는 것은 제출된 어웨이터블을 취소하지 않습니다. 예를 들어, 예외를 호출자에게 전파한 후 gather가 완료된 것으로 표시될 수 있습니다, 따라서 gather에서 (어웨이터블 중 하나에 의해 발생한) 예외를 포착한 후 gather.cancel()을 호출하는 것은 다른 어웨이터블을 취소하지 않습니다.

버전 3.7에서 변경: gather 자체가 취소되면, return_exceptions와 관계없이 취소가 전파됩니다.

버전 3.10에서 변경: loop 매개 변수를 제거했습니다.

버전 3.10부터 폐지됨: 위치 인자가 제공되지 않거나 모든 위치 인자가 Future와 같은 객체가 아니며 실행 중인 이벤트 루프가 없는 경우 폐지 경고(Deprecation warning)가 발생합니다.

즉시 실행 태스크 팩토리

asyncio.eager_task_factory(loop, coro, *, name=None, context=None)

즉시 실행 태스크를 위한 태스크 팩토리입니다.

이 팩토리를 사용할 경우(loop.set_task_factory(asyncio.eager_task_factory)), 코루틴은 Task 생성 중에 동기적으로 실행을 시작합니다. 태스크가 차단(block)되는 경우에만 이벤트 루프에 예약됩니다. 이는 동기적으로 완료되는 코루틴의 경우 루프 예약 오버헤드를 피할 수 있어 성능 개선 효과가 있을 수 있습니다.

이 기능이 유용한 일반적인 예는 가능한 경우 실제 I/O를 피하기 위해 캐싱이나 메모이제이션을 사용하는 코루틴입니다.

참고

코루틴의 즉시 실행은 의미론적인 변화입니다. 코루틴이 값을 반환하거나 예외를 발생시키면 태스크가 이벤트 루프에 예약되지 않습니다. 코루틴 실행이 차단되면 태스크가 이벤트 루프에 예약됩니다. 이 변경은 기존 애플리케이션에서 동작 변화를 일으킬 수 있습니다. 예를 들어, 애플리케이션의 태스크 실행 순서가 변경될 가능성이 높습니다.

Added in version 3.12.

asyncio.create_eager_task_factory(custom_task_constructor)

기본 Task 대신 제공된 custom_task_constructor 를 사용하여 새로운 태스크를 생성할 때, eager_task_factory() 와 유사한 즉시 실행 태스크 팩토리를 생성합니다.

custom_task_constructorTask.__init__ 의 시그니처와 일치하는 시그니처를 가진 callable 이어야 합니다. 해당 callable은 asyncio.Task 와 호환되는 객체를 반환해야 합니다.

이 함수는 loop.set_task_factory(factory) 를 통해 이벤트 루프의 태스크 팩토리로 사용되도록 설계된 callable 을 반환합니다.

Added in version 3.12.

취소로부터 보호하기

awaitable asyncio.shield(aw)

어웨이터블 객체취소로부터 보호합니다.

aw가 코루틴이면 자동으로 태스크로 예약됩니다.

다음 문장:

task = asyncio.create_task(something())
res = await shield(task)

은 다음과 동등합니다:

res = await something()

, 그것을 포함하는 코루틴이 취소되면, something()에서 실행 중인 태스크는 취소되지 않는다는 것만 예외입니다. something()의 관점에서는, 취소가 일어나지 않았습니다. 호출자는 여전히 취소되었고, “await” 표현식은 여전히 CancelledError를 발생시킵니다.

something()가 다른 수단(즉, 그 안에서 스스로)에 의해 취소되면, shield()도 취소됩니다.

취소를 완전히 무시하려면(권장되지 않습니다), 다음과 같이 shield() 함수를 try/except 절과 결합해야 합니다:

task = asyncio.create_task(something())
try:
    res = await shield(task)
except CancelledError:
    res = None

중요

실행 중에 태스크가 사라지는 것을 방지하기 위해 이 함수에 전달된 태스크의 참조를 저장하십시오. 이벤트 루프는 태스크에 대한 약한 참조(weak reference)만 유지합니다. 다른 곳에서 참조되지 않는 태스크는 완료되기 전이라도 언제든 가비지 컬렉션될 수 있습니다.

버전 3.10에서 변경: loop 매개 변수를 제거했습니다.

버전 3.10부터 폐지됨: aw 가 Future와 같은 객체가 아니며 실행 중인 이벤트 루프가 없는 경우 폐지 경고가 발생합니다.

시간제한

asyncio.timeout(delay)

무언가를 기다리는 데 소요되는 시간을 제한하는 데 사용할 수 있는 비동기 컨텍스트 관리자 를 반환합니다.

delayNone 또는 대기할 float/int 초 수입니다. delayNone이면, 시간 제한이 적용되지 않습니다; 컨텍스트 관리자가 만들어질 때 지연 시간이 아려지지 않은 경우 유용할 수 있습니다.

어느 경우든 컨텍스트 관리자는 생성 후 Timeout.reschedule() 을 사용하여 다시 예약할 수 있습니다.

예:

async def main():
    async with asyncio.timeout(10):
        await long_running_task()

long_running_task 이 완료되는 데 10초 이상 걸리면 컨텍스트 관리자가 현재 태스크를 취소하고 발생하는 asyncio.CancelledError 를 내부적으로 처리하여, 포착 및 처리가 가능한 TimeoutError 로 변환합니다.

참고

asyncio.timeout() 컨텍스트 관리자는 asyncio.CancelledErrorTimeoutError 로 변환하며, 이는 TimeoutError 가 컨텍스트 관리자 외부 에서만 포착될 수 있음을 의미합니다.

TimeoutError 를 처리하는 예제:

async def main():
    try:
        async with asyncio.timeout(10):
            await long_running_task()
    except TimeoutError:
        print("The long operation timed out, but we've handled it.")

    print("This statement will run regardless.")

asyncio.timeout() 에 의해 생성된 컨텍스트 관리자는 다른 마감 시한으로 재설정하고 조사할 수 있습니다.

class asyncio.Timeout(when)

기한이 지난 코루틴을 취소하기 위한 비동기 컨텍스트 관리자 입니다.

Timeout 을 직접 인스턴스화하는 대신 asyncio.timeout() 또는 asyncio.timeout_at() 을 사용하는 것을 권장합니다.

when 은 이벤트 루프의 시계로 측정된, 컨텍스트가 만료되어야 하는 절대 시간이어야 합니다:

  • whenNone 인 경우 시간 초과가 발생하지 않습니다.

  • `when < loop.time() 일 경우, 다음 이벤트 루프 반복에서 시간 초과가 발생합니다.

when() float | None

현재 마감 시한을 반환하며, 설정되어 있지 않으면 None 을 반환합니다.

reschedule(when: float | None)

시간 초과를 재설정합니다.

expired() bool

컨텍스트 관리자가 마감 시한을 초과했는지 여부를 반환합니다.

예:

async def main():
    try:
        # 시작 시 시간 제한을 알 수 없어서 ``None`` 을 전달합니다.
        async with asyncio.timeout(None) as cm:
            # 이제 시간 제한을 알게되어, 재조정합니다.
            new_deadline = get_running_loop().time() + 10
            cm.reschedule(new_deadline)

            await long_running_task()
    except TimeoutError:
        pass

    if cm.expired():
        print("Looks like we haven't finished on time.")

시간 초과 컨텍스트 관리자는 안전하게 중첩될 수 있습니다.

Added in version 3.11.

asyncio.timeout_at(when)

asyncio.timeout() 과 유사하지만, when 이 대기 중단을 위한 절대 시간 또는 None 인 점이 다릅니다.

예:

async def main():
    loop = get_running_loop()
    deadline = loop.time() + 20
    try:
        async with asyncio.timeout_at(deadline):
            await long_running_task()
    except TimeoutError:
        print("The long operation timed out, but we've handled it.")

    print("This statement will run regardless.")

Added in version 3.11.

async asyncio.wait_for(aw, timeout)

aw 어웨이터블이 제한된 시간 내에 완료될 때까지 기다립니다.

aw가 코루틴이면 자동으로 태스크로 예약됩니다.

timeoutNone 또는 대기할 float 나 int 초 수입니다. timeoutNone이면 퓨처가 완료될 때까지 블록합니다.

시간 초과가 발생하면, 태스크를 취소하고 TimeoutError를 발생시킵니다.

태스크 취소를 피하려면, shield()로 감싸십시오.

이 함수는 퓨처가 실제로 취소될 때까지 대기하므로, 총 대기 시간이 timeout을 초과할 수 있습니다. 취소하는 동안 예외가 발생하면, 전파됩니다.

대기가 취소되면, 퓨처 aw도 취소됩니다.

예:

async def eternity():
    # 1시간 동안 잠잡니다
    await asyncio.sleep(3600)
    print('yay!')

async def main():
    # 최대 1초간 대기합니다
    try:
        await asyncio.wait_for(eternity(), timeout=1.0)
    except TimeoutError:
        print('timeout!')

asyncio.run(main())

# 예상 출력:
#
#     timeout!

버전 3.7에서 변경: 시간 초과로 인해 aw가 취소되면, wait_foraw가 취소될 때까지 대기합니다. 이전에는 TimeoutError가 즉시 발생했습니다.

버전 3.10에서 변경: loop 매개 변수를 제거했습니다.

버전 3.11에서 변경: asyncio.TimeoutError 대신 TimeoutError 를 발생시킵니다.

대기 프리미티브

async asyncio.wait(aws, *, timeout=None, return_when=ALL_COMPLETED)

aws 이터러블에 있는 FutureTask 인스턴스를 동시에 실행하고, return_when에 의해 지정된 조건을 만족할 때까지 블록합니다.

aws 이터러블은 비어있을 수 없습니다.

두 집합의 태스크/퓨처를 반환합니다: (done, pending).

사용법:

done, pending = await asyncio.wait(aws)

timeout(float나 int)을 지정하면, 반환하기 전에 대기할 최대 시간(초)을 제어할 수 있습니다.

이 함수는 TimeoutError를 발생시키지 않음에 유의하십시오. 시간 초과가 발생할 때 완료되지 않은 퓨처나 태스크는 단순히 두 번째 집합으로 반환됩니다.

return_when는 이 함수가 언제 반환해야 하는지 나타냅니다. 다음 상수 중 하나여야 합니다:

상수

설명

asyncio.FIRST_COMPLETED

퓨처가 하나라도 끝나거나 취소될 때 함수가 반환됩니다.

asyncio.FIRST_EXCEPTION

퓨처가 하나라도 예외를 일으켜 끝나면 함수가 반환됩니다. 어떤 퓨처도 예외를 일으키지 않으면 ALL_COMPLETED와 같습니다.

asyncio.ALL_COMPLETED

모든 퓨처가 끝나거나 취소되면 함수가 반환됩니다.

wait_for()와 달리, wait()는 시간 초과가 발생할 때 퓨처를 취소하지 않습니다.

버전 3.10에서 변경: loop 매개 변수를 제거했습니다.

버전 3.11에서 변경: 코루틴 객체를 wait()로 직접 전달하는 것은 금지됩니다.

버전 3.12에서 변경: 태스크를 yield하는 제너레이터에 대한 지원을 추가했습니다.

asyncio.as_completed(aws, *, timeout=None)

aws 이터러블에 있는 어웨이터블 객체를 동시에 실행합니다. 코루틴의 이터레이터를 반환합니다. 반환된 객체는 어웨이터블이 완료될 때마다 그 결과를 얻기 위해 이터레이트 할 수 있습니다.

as_completed() 이 반환하는 객체는 비동기 이터레이터 또는 일반 이터레이터 로 반복할 수 있습니다. 비동기 이터레이션을 사용할 때, 원래 제공된 어웨이터블이 태스크나 퓨처인 경우 그대로 yield됩니다. 이를 통해 이전에 예약된 태스크와 그 결과를 연결하기 쉬워집니다. 예:

ipv4_connect = create_task(open_connection("127.0.0.1", 80))
ipv6_connect = create_task(open_connection("::1", 80))
tasks = [ipv4_connect, ipv6_connect]

async for earliest_connect in as_completed(tasks):
    # earliest_connect 가 완료했습니다. 결과는 어웨이트하거나
    # earliest_connect.result() 를 호출해서 얻을 수 있습니다.
    reader, writer = await earliest_connect

    if earliest_connect is ipv6_connect:
        print("IPv6 connection established.")
    else:
        print("IPv4 connection established.")

비동기 이터레이션 중에, 태스크나 퓨처가 아닌 제공된 어웨이터블의 경우 암시적으로 생성된 태스크가 yield됩니다.

일반 이터레이터로 사용될 때, 매 반복마다 다음 완료된 어웨이터블의 결과를 반환하거나 예외를 발생시키는 새로운 코루틴을 yield합니다. 이 패턴은 Python 3.13 이전 버전과 호환됩니다:

ipv4_connect = create_task(open_connection("127.0.0.1", 80))
ipv6_connect = create_task(open_connection("::1", 80))
tasks = [ipv4_connect, ipv6_connect]

for next_connect in as_completed(tasks):
    # next_connect 는 원래 태스크 객체 중 하나가 아닙니다.
    # 결과 값을 얻거나 다음에 완료되는 어웨이터블의 예외를 발생시키려면
    # 반드시 어웨이트해야 합니다.
    reader, writer = await next_connect

모든 어웨이터블이 완료되기 전에 시간 초과가 발생하면 TimeoutError`가 발생합니다. 이는 비동기 이터레이션 중의 ``async for` 루프 또는 일반 이터레이션 중에 yield되는 코루틴에 의해 발생합니다.

버전 3.10에서 변경: loop 매개 변수를 제거했습니다.

버전 3.10부터 폐지됨: aws 반복 가능 객체 내의 모든 어웨이터블이 Future와 같은 객체가 아니며 실행 중인 이벤트 루프가 없는 경우 폐지 경고가 발생합니다.

버전 3.12에서 변경: 태스크를 yield하는 제너레이터에 대한 지원을 추가했습니다.

버전 3.13에서 변경: 결과를 이제 비동기 이터레이터 또는 일반 이터레이터 로 사용할 수 있습니다(이전에는 일반 이터레이터만 가능했습니다).

스레드에서 실행하기

async asyncio.to_thread(func, /, *args, **kwargs)

별도의 스레드에서 func 함수를 비동기적으로 실행합니다.

이 함수에 제공된 모든 *args 와 **kwargs 는 func로 직접 전달됩니다. 또한, 현재 contextvars.Context가 전파되어, 이벤트 루프 스레드의 컨텍스트 변수가 별도의 스레드에서 액세스 될 수 있습니다.

func의 최종 결과를 얻기 위해 어웨이트 할 수 있는 코루틴을 반환합니다.

이 코루틴 함수는 메인 스레드에서 실행된다면 이벤트 루프를 블록할 IO 병목 함수/메서드를 실행하는 데 주로 사용됩니다. 예를 들면:

def blocking_io():
    print(f"start blocking_io at {time.strftime('%X')}")
    # time.sleep()은 파일 연산과 같은 임의의 블로킹 IO 병목 연산으로 대체될
    # 수 있음에 유의하십시오.
    time.sleep(1)
    print(f"blocking_io complete at {time.strftime('%X')}")

async def main():
    print(f"started main at {time.strftime('%X')}")

    await asyncio.gather(
        asyncio.to_thread(blocking_io),
        asyncio.sleep(1))

    print(f"finished main at {time.strftime('%X')}")


asyncio.run(main())

# 예상 출력:
#
# started main at 19:50:53
# start blocking_io at 19:50:53
# blocking_io complete at 19:50:54
# finished main at 19:50:54

코루틴에서 blocking_io()를 직접 호출하면 그동안 이벤트 루프가 블록 되어 추가 1초의 실행 시간이 발생합니다. 대신, asyncio.to_thread()를 사용하면, 이벤트 루프를 블록하지 않고 별도의 스레드에서 실행할 수 있습니다.

참고

GIL로 인해, asyncio.to_thread()는 일반적으로 IO 병목 함수를 비 블로킹으로 만드는 데만 사용할 수 있습니다. 그러나, GIL을 반납하는 확장 모듈이나 GIL이 없는 대체 파이썬 구현의 경우, asyncio.to_thread()를 CPU 병목 함수에도 사용할 수 있습니다.

Added in version 3.9.

다른 스레드에서 예약하기

asyncio.run_coroutine_threadsafe(coro, loop)

주어진 이벤트 루프에 코루틴을 제출합니다. 스레드 안전합니다.

다른 OS 스레드에서 결과를 기다리는 concurrent.futures.Future를 반환합니다.

이 함수는 이벤트 루프가 실행 중인 스레드가 아닌, 다른 OS 스레드에서 호출하기 위한 것입니다. 예:

def in_thread(loop: asyncio.AbstractEventLoop) -> None:
    # 차단되는 IO 실행
    pathlib.Path("example.txt").write_text("hello world", encoding="utf8")

    # 코루틴 생성
    coro = asyncio.sleep(1, result=3)

    # 지정된 루프에 코루틴 제출
    future = asyncio.run_coroutine_threadsafe(coro, loop)

    # 선택적 시간제한 인자로 결과를 기다림
    assert future.result(timeout=2) == 3

async def amain() -> None:
    # 실행 중인 루프 가져오기
    loop = asyncio.get_running_loop()

    # 스레드에서 무언가 실행
    await asyncio.to_thread(in_thread, loop)

반대 방식으로 실행하는 것도 가능합니다. 예:

@contextlib.contextmanager
def loop_in_thread() -> Generator[asyncio.AbstractEventLoop]:
    loop_fut = concurrent.futures.Future[asyncio.AbstractEventLoop]()
    stop_event = asyncio.Event()

    async def main() -> None:
        loop_fut.set_result(asyncio.get_running_loop())
        await stop_event.wait()

    with concurrent.futures.ThreadPoolExecutor(1) as tpe:
        complete_fut = tpe.submit(asyncio.run, main())
        for fut in concurrent.futures.as_completed((loop_fut, complete_fut)):
            if fut is loop_fut:
                loop = loop_fut.result()
                try:
                    yield loop
                finally:
                    loop.call_soon_threadsafe(stop_event.set)
            else:
                fut.result()

# 다른 스레드에서 루프 생성
with loop_in_thread() as loop:
    # 코루틴 생성
    coro = asyncio.sleep(1, result=3)

    # 지정된 루프로 코루틴 제출
    future = asyncio.run_coroutine_threadsafe(coro, loop)

    # 선택적 시간제한 인자로 결과 대기
    assert future.result(timeout=2) == 3

코루틴에서 예외가 발생하면, 반환된 Future에 통지됩니다. 또한, 이벤트 루프에서 태스크를 취소하는 데 사용할 수 있습니다:

try:
    result = future.result(timeout)
except TimeoutError:
    print('The coroutine took too long, cancelling the task...')
    future.cancel()
except Exception as exc:
    print(f'The coroutine raised an exception: {exc!r}')
else:
    print(f'The coroutine returned: {result!r}')

설명서의 동시성과 다중 스레드 절을 참조하십시오.

다른 asyncio 함수와 달리, 이 함수는 loop 인자가 명시적으로 전달되어야 합니다.

Added in version 3.5.1.

인트로스펙션

asyncio.current_task(loop=None)

현재 실행 중인 Task 인스턴스를 반환하거나 태스크가 실행되고 있지 않으면 None을 반환합니다.

loopNone이면, 현재 루프를 가져오는 데 get_running_loop()가 사용됩니다.

Added in version 3.7.

asyncio.all_tasks(loop=None)

루프에 의해 실행되는 아직 완료되지 않은 Task 객체 집합을 반환합니다.

loopNone이면, 현재 루프를 가져오는 데 get_running_loop()가 사용됩니다.

Added in version 3.7.

asyncio.iscoroutine(obj)

obj가 코루틴 객체면 True를 반환합니다.

Added in version 3.4.

Task 객체

class asyncio.Task(coro, *, loop=None, name=None, context=None, eager_start=False)

파이썬 코루틴을 실행하는 퓨처류 객체입니다. 스레드 안전하지 않습니다.

태스크는 이벤트 루프에서 코루틴을 실행하는 데 사용됩니다. 만약 코루틴이 Future를 기다리고 있다면, 태스크는 코루틴의 실행을 일시 중지하고 Future의 완료를 기다립니다. 퓨처가 완료되면, 감싸진 코루틴의 실행이 다시 시작됩니다.

이벤트 루프는 협업 스케줄링을 사용합니다: 이벤트 루프는 한 번에 하나의 Task를 실행합니다. Task가 Future의 완료를 기다리는 동안, 이벤트 루프는 다른 태스크, 콜백을 실행하거나 IO 연산을 수행합니다.

테스크를 만들려면 고수준 asyncio.create_task() 함수를 사용하거나, 저수준 loop.create_task()ensure_future() 함수를 사용하십시오. 태스크의 인스턴스를 직접 만드는 것은 권장되지 않습니다.

실행 중인 Task를 취소하려면 cancel() 메서드를 사용하십시오. 이 메서드를 호출하면 해당 Task가 감싼 코루틴으로 CancelledError 예외를 던집니다. 코루틴이 취소 중에 퓨처(future)와 유사한 객체를 기다리고 있는 경우, 대기 중인 객체도 취소됩니다.

cancelled()는 태스크가 취소되었는지 확인하는 데 사용할 수 있습니다. 이 메서드는 감싼 코루틴이 CancelledError 예외를 억제하지 않고 실제로 취소되었으면 True를 반환합니다.

asyncio.TaskFuture.set_result()Future.set_exception()을 제외한 모든 API를 Future에서 상속받습니다.

선택적인 키워드 전용 context 인자를 통해 coro 가 실행될 사용자 정의 contextvars.Context 를 지정할 수 있습니다. context 가 제공되지 않으면, Task는 현재 컨텍스트를 복사하고 이후 그 복사된 컨텍스트에서 코루틴을 실행합니다.

선택적인 키워드 전용 eager_start 인자를 사용하여 태스크 생성 시점에 asyncio.Task 의 실행을 즉시 시작할 수 있습니다. 이 값이 True 이고 이벤트 루프가 실행 중이면, 태스크는 코루틴이 처음으로 차단(block)될 때까지 코루틴 실행을 즉시 시작합니다. 코루틴이 차단 없이 반환되거나 예외를 발생시키면, 해당 태스크는 즉시 완료되며 이벤트 루프로의 스케줄링 단계를 생략합니다.

Task는 감싼 코루틴의 반환 타입에 대해 generic 입니다.

버전 3.7에서 변경: contextvars 모듈에 대한 지원이 추가되었습니다.

버전 3.8에서 변경: name 매개 변수가 추가되었습니다.

버전 3.10부터 폐지됨: loop 가 지정되지 않았으며 실행 중인 이벤트 루프가 없는 경우 폐지 경고가 발생합니다.

버전 3.11에서 변경: context 매개 변수가 추가되었습니다.

버전 3.12에서 변경: eager_start 매개 변수가 추가되었습니다.

done()

Task가 완료(done)되었으면 True를 반환합니다.

감싼 코루틴이 값을 반환하거나 예외를 일으키거나, Task가 취소되면 Task는 완료(done)됩니다.

result()

Task의 결과를 반환합니다.

Task가 완료(done)되었으면 감싼 코루틴의 결과가 반환됩니다 (또는 코루틴이 예외를 발생시켰으면 해당 예외가 다시 발생합니다).

태스크가 취소(cancelled)되었으면, 이 메서드는 CancelledError 예외를 발생시킵니다.

태스크 결과를 아직 사용할 수 없으면, 이 메서드는 InvalidStateError 예외를 발생시킵니다.

exception()

Task의 예외를 반환합니다.

감싼 코루틴이 예외를 발생시키면, 그 예외가 반환됩니다. 감싼 코루틴이 정상적으로 반환되면, 이 메서드는 None을 반환합니다.

태스크가 취소(cancelled)되었으면, 이 메서드는 CancelledError 예외를 발생시킵니다.

태스크가 아직 완료(done)되지 않았으면, 이 메서드는 InvalidStateError 예외를 발생시킵니다.

add_done_callback(callback, *, context=None)

태스크가 완료(done)될 때 실행할 콜백을 추가합니다.

이 메서드는 저수준 콜백 기반 코드에서만 사용해야 합니다.

자세한 내용은 Future.add_done_callback() 설명서를 참조하십시오.

remove_done_callback(callback)

콜백 목록에서 callback을 제거합니다.

이 메서드는 저수준 콜백 기반 코드에서만 사용해야 합니다.

자세한 내용은 Future.remove_done_callback() 설명서를 참조하십시오.

get_stack(*, limit=None)

이 Task의 스택 프레임 리스트를 돌려줍니다.

감싼 코루틴이 완료되지 않았으면, 일시 정지된 곳의 스택을 반환합니다. 코루틴이 성공적으로 완료되었거나 취소되었으면 빈 리스트가 반환됩니다. 코루틴이 예외로 종료되었으면, 이것은 트레이스백 프레임의 리스트를 반환합니다.

프레임은 항상 가장 오래된 것부터 순서대로 정렬됩니다.

일시 정지된 코루틴에서는 하나의 스택 프레임만 반환됩니다.

선택적 limit 인자는 반환할 최대 프레임 수를 설정합니다; 기본적으로 사용 가능한 모든 프레임이 반환됩니다. 반환되는 리스트의 순서는 스택과 트레이스백 중 어느 것이 반환되는지에 따라 다릅니다: 스택은 최신 프레임이 반환되지만, 트레이스백은 가장 오래된 프레임이 반환됩니다. (이는 traceback 모듈의 동작과 일치합니다.)

print_stack(*, limit=None, file=None)

이 Task의 스택이나 트레이스백을 인쇄합니다.

이것은 get_stack()으로 얻은 프레임에 대해 traceback 모듈과 유사한 출력을 생성합니다.

limit 인자는 get_stack()에 직접 전달됩니다.

file 인자는 출력이 기록되는 I/O 스트림입니다; 기본적으로 출력은 sys.stdout에 기록됩니다.

get_coro()

Task로 싸인 코루틴 객체를 반환합니다.

참고

이 메서드는 이미 즉시 완료된(eagerly) 태스크에 대해 None 을 반환합니다. 자세한 내용은 Eager Task Factory 를 참조하십시오.

Added in version 3.8.

버전 3.12에서 변경: 새로 추가된 즉시 태스크 실행 기능으로 인해 결과가 None 일 수 있습니다.

get_context()

태스크와 연관된 contextvars.Context 객체를 반환합니다.

Added in version 3.12.

get_name()

Task의 이름을 반환합니다.

Task에 명시적으로 이름이 지정되지 않으면, 기본 asyncio Task 구현은 인스턴스화 중에 기본 이름을 생성합니다.

Added in version 3.8.

set_name(value)

Task의 이름을 설정합니다.

value 인자는 모든 객체가 될 수 있으며, 문자열로 변환됩니다.

기본 Task 구현에서, 이름은 태스크 객체의 repr() 출력에 표시됩니다.

Added in version 3.8.

cancel(msg=None)

Task 취소를 요청합니다.

Task가 이미 done 또는 cancelled 상태이면 False 를 반환하고, 그렇지 않으면 True 를 반환합니다.

이 메서드는 이벤트 루프의 다음 사이클에서 감싼 코루틴으로 CancelledError 예외를 던져넣도록 합니다.

그러면 코루틴은 try … … except CancelledErrorfinally 블록으로 정리하거나 예외를 억제하여 요청을 거부할 수 있습니다. 따라서, Future.cancel()와 달리 Task.cancel()은 Task가 취소됨을 보장하지는 않습니다. 하지만 취소를 완전히 억제하는 것은 일반적이지 않고, 그렇게 하지 말도록 적극적으로 권합니다. 그럼에도 불구하고 코루틴이 취소를 억제하기로 결정한 경우, 예외를 잡는 것 외에 Task.uncancel() 호출도 해야 합니다.

취소되는 태스크가 현재 퓨처와 유사한 객체를 기다리고 있는 경우, 해당 대기 객체도 취소됩니다. 이 취소는 대기 중인 모든 객체의 체인 전체로 전파됩니다.

버전 3.9에서 변경: msg 매개 변수가 추가되었습니다.

버전 3.11에서 변경: msg 파라미터는 취소된 태스크에서 이를 기다리는(await) 대상에게 전달됩니다.

다음 예는 코루틴이 취소 요청을 가로채는 방법을 보여줍니다:

async def cancel_me():
    print('cancel_me(): before sleep')

    try:
        # 1시간 동안 기다립니다
        await asyncio.sleep(3600)
    except asyncio.CancelledError:
        print('cancel_me(): cancel sleep')
        raise
    finally:
        print('cancel_me(): after sleep')

async def main():
    # "cancel_me" Task를 만듭니다
    task = asyncio.create_task(cancel_me())

    # 1초 동안 기다립니다
    await asyncio.sleep(1)

    task.cancel()
    try:
        await task
    except asyncio.CancelledError:
        print("main(): cancel_me is cancelled now")

asyncio.run(main())

# 예상 출력:
#
#     cancel_me(): before sleep
#     cancel_me(): cancel sleep
#     cancel_me(): after sleep
#     main(): cancel_me is cancelled now
cancelled()

Task가 취소(cancelled)되었으면 True를 반환합니다.

Task는 cancel()로 취소가 요청되고 감싼 코루틴이 자신에게 전달된 CancelledError 예외를 확산할 때 최소(cancelled)됩니다.

uncancel()

이 태스크에 대한 취소 요청 횟수를 감소시킵니다.

남아 있는 취소 요청 횟수를 반환합니다.

취소된 태스크의 실행이 완료되면 uncancel() 을 추가로 호출해도 효과가 없다는 점에 유의하십시오.

Added in version 3.11.

이 메서드는 asyncio 내부에서 사용되며 엔드 유저 코드가 사용할 것으로 예상되지 않습니다. 특히 태스크가 성공적으로 취소 해제(uncancel)되면, 태스크 그룹asyncio.timeout() 과 같은 구조화된 동시성 요소들이 계속 실행될 수 있으며, 취소가 해당 구조적 블록 내로 제한됩니다. 예시:

async def make_request_with_timeout():
    try:
        async with asyncio.timeout(1):
            # 시간 제한의 영향을 받는 구조화된 블록:
            await make_request()
            await make_another_request()
    except TimeoutError:
        log("There was a timeout")
    # 시간 제한의 영향을 받지 않는 바깥 코드:
    await unrelated_code()

make_request()make_another_request() 를 포함하는 블록은 타임아웃으로 인해 취소될 수 있지만, unrelated_code() 는 타임아웃의 경우에도 계속 실행되어야 합니다. 이는 uncancel() 로 구현됩니다. TaskGroup 컨텍스트 관리자는 uncancel() 을 유사한 방식으로 사용합니다.

엔드 유저 코드가 어떤 이유로든 CancelledError 를 잡아 취소를 억제하는 경우, 취소 상태를 제거하기 위해 이 메서드를 호출해야 합니다.

이 메서드가 취소 횟수를 0으로 줄일 때, 이전의 cancel() 호출에 의해 태스크로 CancelledError`가 던져지도록 설정되었는지 확인합니다. 아직 발생하지 않았다면 해당 설정을 취소합니다(내부 ``_must_cancel` 플래그를 재설정함).

버전 3.13에서 변경: 0에 도달했을 때 대기 중인 취소 요청을 철회하도록 변경되었습니다.

cancelling()

이 태스크에 대한 대기 중인 취소 요청 횟수를 반환합니다. 즉, cancel() 호출 횟수에서 uncancel() 호출 횟수를 뺀 값입니다.

이 숫자가 0보다 크더라도 태스크가 여전히 실행 중이라면, cancelled() 는 여전히 False 를 반환한다는 점에 유의하십시오. 이는 취소 요청이 0으로 줄어들 때까지 uncancel() 을 호출하여 이 수치를 낮출 수 있고, 그 결과로 태스크가 최종적으로 취소되지 않을 수도 있기 때문입니다.

이 메서드는 asyncio 내부에서 사용되며 엔드 유저 코드가 사용할 것으로 예상되지 않습니다. 자세한 내용은 uncancel() 을 참조하십시오.

Added in version 3.11.

분실물 보관소