3/30 파이썬 비동기 프로그래밍
⚙️ 1. 비동기 함수 개념 정리 분류 함수/키워드 의미 (비유) 주요 역할 정의 async def 예약 가능한 함수 호출 즉시 실행되지 않고, 나중에 실행할 코루틴 객체를 생성합니다. 제어 await 기다리는 동안 양보 작업 완료를 기다리는 동안 이
⚙️ 1. 비동기 함수 개념 정리
| 분류 | 함수/키워드 | 의미 (비유) | 주요 역할 |
|---|---|---|---|
| 정의 | async def |
예약 가능한 함수 | 호출 즉시 실행되지 않고, 나중에 실행할 코루틴 객체를 생성합니다. |
| 제어 | await |
기다리는 동안 양보 | 작업 완료를 기다리는 동안 이벤트 루프에 제어권을 넘겨 다른 작업이 실행되게 합니다. |
| 실행 | asyncio.run() |
엔진 시동 | 이벤트 루프를 생성하고 메인 코루틴을 실행한 뒤 안전하게 종료합니다. |
| 조율 | asyncio.gather() |
동시 실행 | 여러 비동기 작업을 한꺼번에 시작하고, 모두 끝날 때까지 기다려 결과를 모읍니다. |
| 조율 | asyncio.as_completed() |
빠른 순 처리 | 완료된 작업부터 순서대로 결과를 받을 수 있게 합니다. |
| 관리 | get_running_loop() |
현재 루프 조회 | 현재 실행 중인 이벤트 루프 객체를 가져옵니다. |
| 도구 | httpx.AsyncClient() |
비동기 브라우저 | 비동기 방식으로 HTTP 요청을 보낼 수 있게 해주는 클라이언트입니다. |
💻 2. 실습 코드
import asyncio
import time
import requests
import httpx
URLS = [
"https://www.google.com",
"https://www.python.org",
"https://www.github.com",
"https://www.naver.com",
"https://www.wikipedia.org"
] * 2
# --- [방법 1] 동기 방식: 하나씩 순서대로 실행 ---
def fetch_sync():
print("동기(Sync) 방식 시작...")
start_time = time.perf_counter()
results = []
for url in URLS:
response = requests.get(url)
results.append(response.status_code)
print(f"[Sync] {url} 완료")
end_time = time.perf_counter()
return end_time - start_time
# --- [방법 2] 비동기 방식: 대기 시간에 다른 작업 수행 ---
# 2-1. 개별 URL을 처리하는 코루틴
async def fetch_async_url(client, url):
response = await client.get(url)
print(f"[Async] {url} 완료")
return response.status_code
# 2-2. 여러 비동기 작업을 조율하는 메인 코루틴
async def fetch_async():
print("\\n비동기(Async) 방식 시작...")
start_time = time.perf_counter()
async with httpx.AsyncClient() as client:
tasks = [fetch_async_url(client, url) for url in URLS]
await asyncio.gather(*tasks)
end_time = time.perf_counter()
return end_time - start_time
# --- 프로그램 실행 시작점 ---
if __name__ == "__main__":
sync_duration = fetch_sync()
async_duration = asyncio.run(fetch_async())
print("\\n" + "=" * 30)
print(f"동기 방식 소요 시간 : {sync_duration:.2f}초")
print(f"비동기 방식 소요 시간: {async_duration:.2f}초")
print(f"비동기가 {sync_duration / async_duration:.1f}배 더 빠릅니다!")
print("=" * 30)
🧠 3. 비동기 vs 멀티스레딩
🔥 핵심 개념
- 비동기 = 한 명의 작업자가 여러 작업을 번갈아 처리하는 방식
- 멀티스레딩 = 여러 작업자가 동시에 작업을 처리하는 방식
📊 동시성 vs 병렬성
| 개념 | 설명 |
|---|---|
| 동시성 (Concurrency) | 하나의 스레드가 여러 작업을 번갈아 수행하여 동시에 진행되는 것처럼 보이게 하는 방식 |
| 병렬성 (Parallelism) | 여러 스레드나 여러 코어가 실제로 동시에 작업을 실행하는 방식 |
⚖️ Async vs Thread 비교
| 구분 | 비동기 (Asyncio) | 멀티스레딩 (Threading) |
|---|---|---|
| 스레드 개수 | 1개 (Single Thread) | 여러 개 (Multiple Threads) |
| 관리 주체 | 애플리케이션 / 이벤트 루프 | 운영체제 |
| 리소스 비용 | 낮음 | 높음 |
| 작업 전환 방식 | await 지점에서 협력적으로 전환 |
운영체제 스케줄러가 강제로 전환 |
| 주요 강점 | I/O 대기 시간을 효율적으로 활용 | 실제 병렬 처리 가능 |
❓ 왜 Python은 Async를 많이 사용할까?
파이썬에는 GIL(Global Interpreter Lock)이라는 제약이 있습니다.
이 때문에 멀티스레드를 사용하더라도 CPU 바운드 작업에서는 기대만큼 성능 향상이 크지 않을 수 있습니다.
하지만 웹 요청, 데이터베이스 쿼리, 파일 읽기/쓰기 같은 I/O 작업은 대부분의 시간이 "응답을 기다리는 시간"입니다.
비동기는 바로 이 대기 시간을 다른 작업으로 채우기 때문에, 적은 리소스로도 많은 작업을 효율적으로 처리할 수 있습니다.
🧾 4. 핵심 요약
async는 여러 일을 동시에 “보이게” 처리하는 동시성 모델이다.await는 기다리는 동안 다른 작업에게 순서를 넘기는 핵심 지점이다.- 파이썬 비동기는 특히 네트워크, API 호출, DB 통신 같은 I/O 작업에서 강력하다.
- CPU 연산이 많은 작업은 비동기보다 멀티프로세싱이 더 적합한 경우가 많다.