파이썬 고급편
Advanced Python Series
async/await으로 시작하는 비동기 파이썬: asyncio 기초
개요 및 중요성
현대 웹 애플리케이션과 데이터 처리 시스템에서 **비동기 프로그래밍**은 필수적인 기술이 되었습니다. 파이썬의 asyncio
라이브러리는 동시에 여러 작업을 효율적으로 처리할 수 있게 해주는 강력한 도구입니다.
특히 네트워크 요청, 파일 I/O, 데이터베이스 접근과 같은 **I/O 바운드 작업**에서 극적인 성능 향상을 경험할 수 있습니다. 이번 강의에서는 async/await
키워드부터 시작해서 비동기 프로그래밍의 핵심 개념들을 실습을 통해 학습해보겠습니다.
asyncio 라이브러리 기초
asyncio
는 파이썬 3.4+에서 제공하는 **비동기 I/O 라이브러리**입니다. 이벤트 루프를 기반으로 하여 단일 스레드에서 여러 작업을 동시에 실행할 수 있게 해줍니다.
🎯 핵심 용어 정리
이벤트 루프 (Event Loop)
작업들을 스케줄링하고 실행하는 핵심 엔진
코루틴 (Coroutine)
일시정지하고 재개할 수 있는 함수
태스크 (Task)
이벤트 루프에서 실행되는 코루틴
어웨이터블 (Awaitable)
await 키워드로 기다릴 수 있는 객체
기본 문법 소개
# 코루틴 함수 정의
async def my_coroutine():
print("코루틴 시작")
await asyncio.sleep(1) # 1초 대기 (논블로킹)
print("코루틴 완료")
# 코루틴 실행
async def main():
await my_coroutine()
# 이벤트 루프 실행
asyncio.run(main())
async def
로 코루틴 함수를 정의하고, await
로 다른 코루틴의 완료를 기다립니다.
async/await 키워드 사용법
async
와 await
는 파이썬 비동기 프로그래밍의 핵심 키워드입니다. 이들을 통해 **협력적 멀티태스킹**을 구현할 수 있습니다.
async 함수 정의
함수를 코루틴으로 만드는 키워드
async def fetch_data():
# 비동기 작업 수행
return "데이터"
await 실행 대기
코루틴의 완료를 기다리는 키워드
result = await fetch_data()
print(result) # "데이터"
중요한 규칙
- •
await
는async
함수 내에서만 사용 가능 - • 코루틴 함수를 호출하면 코루틴 객체가 반환됨 (즉시 실행되지 않음)
- •
await
없이 코루틴을 호출하면 경고 발생
이벤트 루프와 태스크 관리
**이벤트 루프**는 asyncio의 핵심으로, 코루틴들을 스케줄링하고 실행하는 역할을 합니다. 여러 작업을 동시에 처리하려면 태스크(Task)로 변환하여 관리해야 합니다.
동시 실행 vs 순차 실행 비교
❌ 순차 실행 (비효율적)
async def sequential():
start = time.time()
await asyncio.sleep(2) # 2초 대기
await asyncio.sleep(2) # 추가 2초 대기
await asyncio.sleep(2) # 추가 2초 대기
print(f"총 소요시간: {time.time()-start:.1f}초")
# 결과: 약 6초
✅ 동시 실행 (효율적)
async def concurrent():
start = time.time()
# 동시에 실행
await asyncio.gather(
asyncio.sleep(2),
asyncio.sleep(2),
asyncio.sleep(2)
)
print(f"총 소요시간: {time.time()-start:.1f}초")
# 결과: 약 2초
I/O 바운드 작업에서의 효율성
비동기 프로그래밍은 특히 **I/O 바운드 작업**에서 진가를 발휘합니다. 네트워크 요청, 파일 읽기, 데이터베이스 쿼리 등에서 대기 시간 동안 다른 작업을 처리할 수 있어 전체적인 성능이 크게 향상됩니다.
예시: 100개의 웹 API를 호출하는 경우
- • 동기 방식: 100 × 0.5초 = 50초
- • 비동기 방식: 최대 0.5초 (네트워크 응답 시간)
비동기 프로그래밍 실습: 간단한 샘플 코드
이번 강의에서 학습한 내용을 바탕으로 직접 실행해 볼 수 있는 실용적인 코드 예제를 살펴보겠습니다. **다중 비동기 작업 동시 실행**과 **간단한 비동기 웹 요청** 예제를 통해 asyncio의 활용법을 익혀보세요.
예제 1 다중 비동기 작업 동시 실행
import asyncio
import time
async def cook_dish(dish_name, cook_time):
"""요리를 만드는 비동기 함수"""
print(f"🍳 {dish_name} 요리 시작!")
await asyncio.sleep(cook_time) # 요리 시간 시뮬레이션
print(f"✅ {dish_name} 요리 완료! ({cook_time}초 소요)")
return f"{dish_name} 완성"
async def prepare_multiple_dishes():
"""여러 요리를 동시에 준비하는 함수"""
print("🏪 레스토랑 오픈! 여러 요리를 동시에 준비합니다.\n")
start_time = time.time()
# 여러 요리를 동시에 시작 (gather 사용)
results = await asyncio.gather(
cook_dish("파스타", 3),
cook_dish("스테이크", 5),
cook_dish("샐러드", 2),
cook_dish("수프", 4)
)
end_time = time.time()
total_time = end_time - start_time
print(f"\n🎉 모든 요리 완료!")
print(f"📋 완성된 요리: {', '.join(results)}")
print(f"⏱️ 총 소요 시간: {total_time:.1f}초")
print(f"💡 순차 처리시 예상 시간: {3+5+2+4}초")
# 실행 함수
async def main():
await prepare_multiple_dishes()
# 프로그램 실행
if __name__ == "__main__":
asyncio.run(main())
💻 실행 결과 예시:
🏪 레스토랑 오픈! 여러 요리를 동시에 준비합니다.
🍳 파스타 요리 시작!
🍳 스테이크 요리 시작!
🍳 샐러드 요리 시작!
🍳 수프 요리 시작!
✅ 샐러드 요리 완료! (2초 소요)
✅ 파스타 요리 완료! (3초 소요)
✅ 수프 요리 완료! (4초 소요)
✅ 스테이크 요리 완료! (5초 소요)
🎉 모든 요리 완료!
📋 완성된 요리: 파스타 완성, 스테이크 완성, 샐러드 완성, 수프 완성
⏱️ 총 소요 시간: 5.0초
💡 순차 처리시 예상 시간: 14초
예제 2 간단한 비동기 웹 요청 (시뮬레이션)
📦 참고: 실제 웹 요청을 위해서는 aiohttp
라이브러리 설치가 필요합니다. (pip install aiohttp
)
import asyncio
import random
import time
async def fetch_url_simulation(url, delay=None):
"""웹 URL을 가져오는 시뮬레이션 함수"""
if delay is None:
delay = random.uniform(0.5, 2.0) # 0.5~2초 랜덤 지연
print(f"🌐 {url} 요청 시작...")
await asyncio.sleep(delay) # 네트워크 지연 시뮬레이션
# 응답 데이터 시뮬레이션
response_data = f"Data from {url} (응답시간: {delay:.1f}초)"
print(f"✅ {url} 응답 완료!")
return response_data
async def batch_fetch_urls():
"""여러 URL을 동시에 요청하는 함수"""
urls = [
"https://api.example1.com/data",
"https://api.example2.com/users",
"https://api.example3.com/posts",
"https://api.example4.com/products",
"https://api.example5.com/analytics"
]
print(f"📡 {len(urls)}개 API 동시 호출 시작!\n")
start_time = time.time()
# 모든 URL을 동시에 요청
try:
responses = await asyncio.gather(
*[fetch_url_simulation(url) for url in urls],
return_exceptions=True # 예외가 발생해도 계속 진행
)
end_time = time.time()
print(f"\n📊 결과 요약:")
print(f"⏱️ 총 소요 시간: {end_time - start_time:.1f}초")
print(f"📈 성공한 요청: {len([r for r in responses if not isinstance(r, Exception)])}개")
# 각 응답 출력
for i, response in enumerate(responses, 1):
if isinstance(response, Exception):
print(f"❌ 요청 {i}: 오류 발생 - {response}")
else:
print(f"📄 응답 {i}: {response}")
except Exception as e:
print(f"❗ 전체 작업 오류: {e}")
# 실제 aiohttp를 사용한 예제 (참고용)
async def real_web_request_example():
"""실제 aiohttp를 사용한 웹 요청 예제 (참고용 - 주석 처리)"""
# import aiohttp
#
# async with aiohttp.ClientSession() as session:
# tasks = []
# urls = ["https://httpbin.org/delay/1", "https://httpbin.org/delay/2"]
#
# for url in urls:
# task = asyncio.create_task(fetch_real_url(session, url))
# tasks.append(task)
#
# responses = await asyncio.gather(*tasks)
# return responses
print("💡 실제 웹 요청을 원한다면 aiohttp를 설치하고 위의 주석을 해제하세요!")
async def main():
print("=== 비동기 웹 요청 시뮬레이션 ===\n")
await batch_fetch_urls()
print("\n" + "="*50)
await real_web_request_example()
# 프로그램 실행
if __name__ == "__main__":
asyncio.run(main())
💻 실행 결과 예시:
📡 5개 API 동시 호출 시작!
🌐 https://api.example1.com/data 요청 시작...
🌐 https://api.example2.com/users 요청 시작...
🌐 https://api.example3.com/posts 요청 시작...
🌐 https://api.example4.com/products 요청 시작...
🌐 https://api.example5.com/analytics 요청 시작...
✅ https://api.example1.com/data 응답 완료!
✅ https://api.example3.com/posts 응답 완료!
✅ https://api.example5.com/analytics 응답 완료!
✅ https://api.example2.com/users 응답 완료!
✅ https://api.example4.com/products 응답 완료!
📊 결과 요약:
⏱️ 총 소요 시간: 1.8초
📈 성공한 요청: 5개
핵심 학습 포인트
asyncio.gather()
로 여러 작업을 동시에 실행
I/O 바운드 작업에서 극적인 성능 향상 가능
async/await
패턴으로 읽기 쉬운 비동기 코드 작성
예외 처리와 함께 안정적인 비동기 프로그램 구현
마무리
이번 강의에서는 파이썬의 **비동기 프로그래밍 핵심 개념**들을 학습했습니다. asyncio
라이브러리와 async/await
키워드를 활용하여 I/O 바운드 작업의 성능을 극적으로 개선하는 방법을 다뤘습니다.
✅ 학습한 핵심 내용
- • 이벤트 루프와 코루틴의 개념
- • async/await 키워드 사용법
- • 동시 실행을 통한 성능 최적화
- • 실용적인 비동기 코드 패턴
🎯 활용 분야
- • 웹 API 다중 호출
- • 파일 시스템 I/O 작업
- • 데이터베이스 쿼리 최적화
- • 실시간 데이터 처리
다음 강의에서는 **병행성과 병렬성의 차이점**을 살펴보고, threading
과 multiprocessing
모듈을 활용한 더 고급 동시성 프로그래밍 기법을 학습하겠습니다. GIL(Global Interpreter Lock)의 개념도 함께 다룰 예정입니다.
'개발 언어 > Python' 카테고리의 다른 글
7강: 고급 데이터 구조 및 collections 모듈 - 파이썬 고급편 (1) | 2025.05.29 |
---|---|
6강: 병행성 vs 병렬성 - 파이썬 고급편 (5) | 2025.05.28 |
텍스트 인식을 위해 PyObjC를 통해 Apple Vision Framework를 사용하는 방법 (1) | 2025.05.28 |
4강: 파이썬 객체 생성의 비밀: 메타클래스 들여다보기 (0) | 2025.05.27 |
3강: 파이썬 고급 - with 구문 마스터하기: 리소스 관리의 효율화 (0) | 2025.05.27 |