본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] 비동기 프로그래밍 Future와 Task 객체의 3가지 핵심 차이와 활용 방법

by Papa Martino V 2026. 3. 17.
728x90

Future와 Task 객체
Future와 Task 객체

 

파이썬의 asyncio 라이브러리를 활용해 비동기 프로그래밍을 구현하다 보면 반드시 마주하게 되는 두 가지 핵심 개념이 있습니다. 바로 FutureTask입니다. 겉보기에는 둘 다 '미래에 완료될 작업'을 나타내는 것처럼 보이지만, 내부적인 동작 방식과 개발자가 제어하는 수준에는 명확한 차이가 존재합니다. 이 글에서는 런타임 수준에서 이 두 객체가 어떻게 관리되는지 분석하고, 실무에서 적재적소에 사용하는 방법을 제안합니다.


1. Future와 Task의 개념적 정의

비동기 프로그래밍에서 이 두 객체는 작업의 상태를 추적하고 결과를 전달하는 통로 역할을 합니다.

  • Future: 비동기 작업의 '결과'를 담는 저수준(Low-level) 객체입니다. 작업이 완료되었는지, 결과값이 무엇인지, 예외가 발생했는지를 기록하는 일종의 '영수증'과 같습니다.
  • Task: Future를 상속받아 구현된 고수준(High-level) 객체입니다. 코루틴을 이벤트 루프에 등록하고 '실행'시키는 스케줄링 주체입니다. 즉, Task는 실행 중인 Future라고 볼 수 있습니다.

2. Future vs Task 핵심 차이 비교 분석

개발자가 직접 결과를 설정하느냐, 아니면 이벤트 루프가 자동으로 관리하느냐가 가장 큰 차이점입니다.

구분 항목 Future 객체 Task 객체 시스템적 차이점
상속 관계 기본 클래스 (Base) Future를 상속함 Task는 Future의 모든 기능을 포함함
작업의 주체 외부에서 결과 주입 필요 코루틴을 감싸서 직접 실행 Task는 스스로 루프에서 동작함
상태 변경 방법 set_result() 직접 호출 코루틴 완료 시 자동 설정 Future는 수동, Task는 자동화됨
주요 사용처 저수준 API, 콜백 기반 연동 일반적인 비동기 비즈니스 로직 대부분의 경우 Task 사용 권장

3. 실무적인 해결 방법: 언제 무엇을 써야 할까?

효율적인 비동기 아키텍처 구성을 위한 2가지 가이드를 제시합니다.

방법 01: 일반적인 비동기 호출에는 Task를 사용하세요

asyncio.create_task()를 호출하면 코루틴이 즉시 이벤트 루프의 큐에 담깁니다. 이는 병렬적으로 여러 작업을 실행할 때 메모리 레이아웃을 가장 효율적으로 사용하는 방법입니다.

방법 02: 동기 코드를 비동기로 래핑할 때는 Future를 고려하세요

외부 라이브러리나 콜백 기반의 동기 라이브러리를 asyncio와 통합해야 할 때, loop.create_future()를 통해 빈 객체를 만들고 작업 완료 시점에 결과를 수동으로 넣어주는 방식을 사용합니다.

4. 실전 샘플 코드 (Sample Example)

Task와 Future의 동작 차이를 직관적으로 이해할 수 있는 코드 예제입니다.


import asyncio

# 1. Future 예제: 수동으로 결과 설정
async def manual_future_demo():
    loop = asyncio.get_running_loop()
    fut = loop.create_future()
    
    # 2초 후 결과를 수동으로 설정하는 예약 작업
    loop.call_later(2, fut.set_result, "Future 결과 완료!")
    
    print("Future 대기 중...")
    result = await fut
    print(f"결과: {result}")

# 2. Task 예제: 코루틴 자동 실행
async def say_hello():
    await asyncio.sleep(1)
    return "Task 작업 완료!"

async def task_demo():
    print("Task 생성 및 스케줄링...")
    task = asyncio.create_task(say_hello())
    
    # Task는 await 시점에 결과가 자동으로 반환됨
    result = await task
    print(f"결과: {result}")

async def main():
    await manual_future_demo()
    print("-" * 30)
    await task_demo()

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

5. 결론 및 최적화 제언

결론적으로 Task는 '실행 중인 작업'을 의미하며, Future는 '언젠가 채워질 데이터 박스'를 의미합니다. 파이썬 비동기 생태계에서 대부분의 개발자가 다루는 객체는 Task입니다. 하지만 프레임워크 개발이나 저수준 네트워크 프로토콜을 다룰 때는 Future의 메커니즘을 정확히 이해해야 메모리 누수를 방지하고 예외 처리를 완벽하게 수행할 수 있습니다.


글의 출처 및 참고 문헌

  • Python Official Documentation: "Futures and Tasks in asyncio"
  • Stack Overflow: "Difference between asyncio.Future and asyncio.Task"
  • Fluent Python, 2nd Edition by Luciano Ramalho (O'Reilly Media)
  • CPython Source Code: Lib/asyncio/tasks.py and Lib/asyncio/futures.py
728x90