PEP 492–Coroutines with Async and Await Syntax#
Python에 비동기 프로그래밍을 위한 async
와 await
구문을 도입하여 코루틴(coroutine)을 명시적으로 정의하고 사용하는 방법을 제안한다.
Python 3.5부터 도입되었다.
기존의 제너레이터 기반 코루틴과 구분되는 네이티브 코루틴을 정의한다.
PEP 492는 비동기 프로그래밍을 더 명확하고 Pythonic하게 만들어 준다.
PEP 492의 주요 내용#
네이티브 코루틴 정의#
await
표현식#
비동기 컨텍스트 관리자#
비동기 반복자#
async for
구문을 통해 비동기 반복자를 사용할 수 있으며, 이는 비동기 데이터 스트림 처리에 적합하다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| class AsyncIterator:
"""비동기 반복자 예제"""
def __init__(self):
self.count = 0
async def __aiter__(self):
return self
async def __anext__(self):
if self.count >= 3:
raise StopAsyncIteration
self.count += 1
return self.count
async def iterate():
async for number in AsyncIterator():
print(number)
|
주요 이점#
- 동시성 처리의 간소화
- 코드의 가독성 향상
- 비동기 코드의 안전성 증가
- 성능 향상 (I/O 바운드 작업의 경우)
사용 사례#
- 웹 애플리케이션
- 네트워크 프로그래밍
- 데이터베이스 작업
- 파일 I/O 작업
주의사항#
- CPU 바운드 작업에는 적합하지 않음 (이 경우 멀티프로세싱 사용 권장)
- 모든 비동기 함수는 await로 실행해야 함
- 일반 함수 안에서는 await를 사용할 수 없음
PEP 492는 Python에서 비동기 프로그래밍을 보다 직관적이고 효율적으로 수행할 수 있게 해준다.
async
와 await
구문은 코드의 가독성을 높이고, 개발자가 비동기 작업의 흐름을 쉽게 이해할 수 있도록 돕는다.
이를 통해 Python은 다른 언어들처럼 현대적인 비동기 프로그래밍 패러다임을 지원하게 됨.
사용 예시#
기본적인 예시#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| import asyncio
# 1. 기본적인 비동기 함수 정의
async def hello_world():
# async def: 이 함수가 비동기 함수임을 선언
print("시작")
# await: 1초 대기하는 비동기 작업을 기다림
await asyncio.sleep(1)
print("1초 후")
return "완료"
# 2. 비동기 함수 실행을 위한 메인 함수
async def main():
# await를 사용해 비동기 함수의 완료를 기다림
result = await hello_world()
print(result)
# 3. 비동기 함수 실행
# asyncio.run(): 비동기 함수를 실행하기 위한 진입점
asyncio.run(main())
|
실용적인 예시#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
| import asyncio
import aiohttp # 비동기 HTTP 클라이언트 라이브러리
# 4. 여러 웹 요청을 비동기적으로 처리하는 예제
async def fetch_url(session, url: str) -> str:
# aiohttp를 사용한 비동기 HTTP 요청
async with session.get(url) as response:
# await를 사용해 응답을 기다림
return await response.text()
async def fetch_multiple_urls():
# 여러 URL을 동시에 처리
urls = [
'http://example.com',
'http://example.org',
'http://example.net'
]
# aiohttp 세션 생성
async with aiohttp.ClientSession() as session:
# 모든 URL에 대한 요청을 동시에 시작
# asyncio.gather: 여러 코루틴을 동시에 실행
tasks = [fetch_url(session, url) for url in urls]
results = await asyncio.gather(*tasks)
return results
# 5. 비동기 컨텍스트 매니저 예제
class AsyncResource:
async def __aenter__(self):
# 비동기 컨텍스트 매니저 진입
print("리소스 획득 중...")
await asyncio.sleep(1)
return self
async def __aexit__(self, exc_type, exc, tb):
# 비동기 컨텍스트 매니저 종료
print("리소스 정리 중...")
await asyncio.sleep(1)
# 6. 비동기 이터레이터 예제
class AsyncCounter:
def __init__(self, limit):
self.limit = limit
self.counter = 0
def __aiter__(self):
return self
async def __anext__(self):
if self.counter < self.limit:
self.counter += 1
await asyncio.sleep(0.1)
return self.counter
raise StopAsyncIteration
# 7. 실제 사용 예제
async def example_usage():
# 비동기 컨텍스트 매니저 사용
async with AsyncResource() as resource:
print("리소스 사용 중")
# 비동기 이터레이터 사용
async for number in AsyncCounter(3):
print(f"카운터: {number}")
# 병렬 작업 처리
tasks = [
asyncio.create_task(asyncio.sleep(1)),
asyncio.create_task(asyncio.sleep(2)),
asyncio.create_task(asyncio.sleep(3))
]
# 모든 태스크가 완료될 때까지 대기
await asyncio.gather(*tasks)
|
참고 및 출처#