개요
이전에 2024.06.26-[Python] asyncio - 비동기 프로그래밍에서 Python에서 비동기 프로그래밍을 하기 위한 라이브러리, 문법, 실행 방법을 알아보았었다.
근데 실제로 사용해 보니 동작 방식에 대한 이해도가 낮아 프로그래밍에 어려움을 느꼈다. 그래서 이번 글에서는 Python 비동기 프로그래밍에서 사용하는 Future와 Task 개념에 대해 정리한다.
Future
Future란 비동기 프로그래밍에서 널리 사용하는 개념으로, 어떠한 작업의 실행 상태와 결과를 저장하는 객체이다.
실행 상태는 PENDING, CANCELLED, FINISHED 값을 가지는데, CANCELLED / FINISHED가 작업의 완료를 의미한다. 실행 결과는 작업의 결과 또는 작업을 진행하면서 발생한 예외 객체가 된다.
참고로 만약 Future가 완료될 때 수행할 함수가 있다면 add_done_callback 함수를 사용하여 등록할 수 있다.
Future는 비동기 함수를 호출한 곳에 지금은 반환 값이 없지만 채워주려는 목적으로 만들어진다. 다만 Future를 외부에 노출하는 것은 권장되지 않기 때문에 직접 다룰 일은 많지 않다.
Task
Task는 Future를 상속받는 클래스로, Future와 동일하게 어떠한 작업의 실행 상태와 결과를 저장한다. 또한 작업의 실행을 개시하는 역할도 함께 수행한다. 실행할 작업은 Task가 생성될 때 전달받은 코루틴이 된다. (전달받은 코루틴은 Task의 _coro 속성에 저장된다.)
Task는 생성되는 즉시 무한 루프를 돌면서 Task를 처리하는 이벤트 루프에게 자신의 __step 메서드(코루틴 실행 메서드)를 호출할 것을 요청한다. 이것을 코루틴이 Task로서 실행되도록 이벤트 루프에 예약한다라고 표현한다.
Task의 __step 메서드가 호출되면 await 키워드를 이용해 다른 코루틴을 부르면서 코루틴 체인을 만들 수 있고, 코루틴을 연쇄적으로 호출하다 Sleep 혹은 I/O 관련 코루틴을 만나면 자신의 실행을 중단하고 이벤트 루프에 제어를 넘기게 된다. 이벤트 루프는 예약된 Task 중 우선순위가 높은 것을 선택하여 실행한다. 이후 중단했던 Task가 다시 실행할 수 있는 상태가 되면 Task는 이벤트 루프에 실행을 예약한다.
한 편 처음 생성된 Task가 코루틴의 실행을 완료하면, 반환 값을 얻어서 Task의 결과 값을 업데이트한다. 이는 Task가 더 이상 이벤트 루프에 실행이 예약될 수 없게 된 상태인 것이다.
참고 문서
https://it-eldorado.com/posts/5ba540c3-98fa-4559-a673-cf232f6978ad
https://tech.buzzvil.com/blog/asyncio-no-2-future/