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 책을 참조하였습니다.

댓글