25장: 비동기 프로그래밍
비동기 프로그래밍은 입출력(I/O) 작업을 효율적으로 처리하는 데 매우 유용한 기법입니다. 파이썬에서는 `asyncio` 모듈을 사용하여 비동기 프로그래밍을 쉽게 구현할 수 있습니다. 이 장에서는 비동기 프로그래밍의 기초 개념과 `asyncio` 모듈을 사용한 예제를 다룹니다.
#### 25.1 비동기 프로그래밍 개요
비동기 프로그래밍은 작업이 완료될 때까지 기다리지 않고 다른 작업을 수행할 수 있는 프로그래밍 방식입니다. 이는 특히 네트워크 요청, 파일 입출력, 데이터베이스 쿼리 등 I/O 바운드 작업에서 유용합니다.
##### 25.1.1 동기와 비동기
- **동기 프로그래밍**: 함수 호출이 완료될 때까지 기다린 후 다음 작업을 수행합니다.
- **비동기 프로그래밍**: 함수 호출이 완료되지 않아도 다른 작업을 수행할 수 있습니다.
```python
import time
def sync_function():
print("동기 함수 시작")
time.sleep(2)
print("동기 함수 종료")
sync_function()
print("다음 작업 수행")
```
```python
import asyncio
async def async_function():
print("비동기 함수 시작")
await asyncio.sleep(2)
print("비동기 함수 종료")
async def main():
await async_function()
print("다음 작업 수행")
asyncio.run(main())
```
#### 25.2 `asyncio` 기초
`asyncio`는 파이썬에서 비동기 프로그래밍을 구현하기 위한 기본 모듈입니다.
##### 25.2.1 코루틴
코루틴은 `async def`로 정의된 함수입니다. 코루틴은 `await` 키워드를 사용하여 다른 코루틴을 호출할 수 있습니다.
```python
import asyncio
async def say_hello():
print("Hello")
await asyncio.sleep(1)
print("World")
asyncio.run(say_hello())
```
##### 25.2.2 태스크
태스크(Task)는 코루틴을 백그라운드에서 실행하도록 스케줄링합니다.
```python
import asyncio
async def task_example():
print("Task 시작")
await asyncio.sleep(2)
print("Task 종료")
async def main():
task = asyncio.create_task(task_example())
await task
asyncio.run(main())
```
##### 25.2.3 `await` 키워드
`await` 키워드는 코루틴을 일시 중지하고, 다른 코루틴이 완료될 때까지 기다립니다.
```python
import asyncio
async def wait_example():
print("대기 시작")
await asyncio.sleep(3)
print("대기 종료")
asyncio.run(wait_example())
```
#### 25.3 고급 `asyncio` 기능
##### 25.3.1 병렬 작업
`asyncio.gather`를 사용하여 여러 코루틴을 병렬로 실행할 수 있습니다.
```python
import asyncio
async def coro1():
await asyncio.sleep(1)
print("coro1 완료")
async def coro2():
await asyncio.sleep(2)
print("coro2 완료")
async def main():
await asyncio.gather(coro1(), coro2())
asyncio.run(main())
```
##### 25.3.2 타임아웃
`asyncio.wait_for`를 사용하여 코루틴에 타임아웃을 설정할 수 있습니다.
```python
import asyncio
async def long_running_task():
await asyncio.sleep(5)
async def main():
try:
await asyncio.wait_for(long_running_task(), timeout=2)
except asyncio.TimeoutError:
print("타임아웃 발생")
asyncio.run(main())
```
##### 25.3.3 큐
`asyncio.Queue`를 사용하여 비동기적으로 안전한 큐를 구현할 수 있습니다.
```python
import asyncio
async def producer(queue):
for i in range(5):
await asyncio.sleep(1)
await queue.put(i)
print(f"생산: {i}")
async def consumer(queue):
while True:
item = await queue.get()
if item is None:
break
print(f"소비: {item}")
await asyncio.sleep(2)
async def main():
queue = asyncio.Queue()
prod = asyncio.create_task(producer(queue))
cons = asyncio.create_task(consumer(queue))
await prod
await queue.put(None) # 종료 신호
await cons
asyncio.run(main())
```
#### 25.4 실제 예제
##### 25.4.1 비동기 HTTP 요청
`aiohttp` 라이브러리를 사용하여 비동기 HTTP 요청을 보낼 수 있습니다. 먼저 `aiohttp`를 설치해야 합니다.
```sh
pip install aiohttp
```
다음은 `aiohttp`를 사용하여 비동기 HTTP 요청을 보내는 예제입니다.
```python
import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
async with aiohttp.ClientSession() as session:
html = await fetch(session, 'https://example.com')
print(html)
asyncio.run(main())
```
##### 25.4.2 비동기 파일 입출력
`aiofiles` 라이브러리를 사용하여 비동기 파일 입출력을 할 수 있습니다. 먼저 `aiofiles`를 설치해야 합니다.
```sh
pip install aiofiles
```
다음은 `aiofiles`를 사용하여 비동기 파일 입출력을 하는 예제입니다.
```python
import aiofiles
import asyncio
async def write_file():
async with aiofiles.open('example.txt', mode='w') as f:
await f.write('Hello, asyncio!')
async def read_file():
async with aiofiles.open('example.txt', mode='r') as f:
contents = await f.read()
print(contents)
async def main():
await write_file()
await read_file()
asyncio.run(main())
```
이상으로, 파이썬에서 비동기 프로그래밍을 사용하는 방법에 대해 알아보았습니다. 비동기 프로그래밍은 특히 I/O 바운드 작업에서 성능을 크게 향상시킬 수 있습니다. 추가로 알고 싶은 내용이나 질문이 있으시면 댓글로 남겨주세요!
---
이 글의 내용은 GoalKicker.com의 Python Notes for Professionals 책을 참조하였습니다.
댓글
댓글 쓰기