데이터 과학 노트

Python async 정리: 사용법부터 스레드와의 차이까지 본문

Development

Python async 정리: 사용법부터 스레드와의 차이까지

Data Scientist Note 2025. 10. 27. 01:09

Python async 완벽 정리: 사용법부터 스레드와의 차이까지

Python의 async/await는 비동기 프로그래밍(asynchronous programming)을 위한 문법이다.
하지만 많은 사람들이 오해하듯, 이것은 스레드(thread)로 구현된 구조가 아니다.
async코루틴(coroutine) 기반으로, 단일 스레드 내에서 동시성(concurrency)을 구현한다.


1. async 기본 개념

  • async def: 비동기 함수를 정의할 때 사용한다.
  • await: 비동기 함수 실행 중 일시 정지(양보) 후, 다른 코루틴이 실행되도록 한다.

이 두 키워드로 Python은 하나의 스레드에서 여러 작업을 비동기적으로 전환할 수 있다.


2. 기본 사용 예시

import asyncio

async def say_hello():
    print("안녕!")
    await asyncio.sleep(1)  # 1초 대기 (비동기)
    print("다시 안녕!")

async def main():
    await say_hello()

asyncio.run(main())

출력:

안녕!
(1초 대기)
다시 안녕!

await asyncio.sleep(1)은 프로그램 전체를 멈추지 않고,
다른 코루틴이 그 시간 동안 실행될 수 있도록 이벤트 루프에 제어를 넘긴다.


3. 여러 작업 동시에 실행하기

import asyncio

async def work(name, delay):
    print(f"{name} 시작")
    await asyncio.sleep(delay)
    print(f"{name} 완료")

async def main():
    await asyncio.gather(
        work("A", 2),
        work("B", 1),
        work("C", 3),
    )

asyncio.run(main())

출력 예시:

A 시작
B 시작
C 시작
B 완료
A 완료
C 완료

asyncio.gather()를 사용하면 여러 비동기 작업을 동시에 실행할 수 있다.
실제로는 병렬이 아니라, 이벤트 루프가 번갈아가며 실행한다.


4. async와 스레드의 차이

구분 asyncio (코루틴) threading (스레드)
실행 방식 단일 스레드 내 협력적 실행 여러 스레드 병렬 실행
전환 방식 await로 명시적 양보 OS가 자동 스케줄링
메모리 사용 가벼움 스레드마다 스택 필요
I/O 효율 매우 높음 보통
CPU 효율 낮음 (GIL 영향) 조금 더 낫지만 여전히 GIL 영향

async논리적 동시성(concurrency)을 제공하지만,
물리적 병렬성(parallelism)은 제공하지 않는다.


5. CPU 연산 작업과 함께 사용하기

async는 I/O 중심의 작업에 최적화되어 있다.
CPU를 많이 사용하는 함수는 이벤트 루프를 막을 수 있으므로
스레드나 프로세스 풀을 함께 사용하는 것이 좋다.

import asyncio
from concurrent.futures import ThreadPoolExecutor
import time

def blocking_task():
    time.sleep(2)
    return "완료"

async def main():
    loop = asyncio.get_running_loop()
    result = await loop.run_in_executor(ThreadPoolExecutor(), blocking_task)
    print(result)

asyncio.run(main())

이 코드는 블로킹 함수(time.sleep)를 별도 스레드에서 실행해
비동기 루프가 멈추지 않게 한다.


6. 결론

  • async스레드가 아닌 코루틴 기반의 비동기 구조다.
  • 이벤트 루프가 여러 작업을 번갈아 실행한다.
  • I/O 중심 작업에 매우 효율적이다.
  • CPU 중심 작업에는 스레드나 프로세스 풀을 병행하는 것이 좋다.

7. 요약

  • async def로 코루틴 정의
  • await로 비동기 작업 일시 정지
  • asyncio.gather()로 여러 작업 동시 실행
  • 스레드가 아니라 이벤트 루프 기반
  • CPU 연산은 run_in_executor()로 분리 실행

'Development' 카테고리의 다른 글

tmux (terminal multiplexer)  (1) 2024.03.27