Python

[Python] asyncio - 비동기 프로그래밍

비번변경 2024. 7. 19. 18:18

개요

2024.06.25-[프로그래밍] 동기(Synchronous) VS 비동기 (Asynchronous)에서 동기, 그리고 비동기에 대한 개념을 살펴보았다.

Python의 경우, 기본적으로 동기 프로그래밍 언어다. 아래와 같이 def 키워드로 생성한 함수는 모두 동기 방식으로 동작한다.

def do_sync():
    return 'sync'

하지만 Python 3.4에서 비동기 프로그래밍을 위한 asyncio 라이브러리가 표준 라이브러리로 추가되고 async/await 키워드가 문법으로 채택되며, Python에서도 외부 라이브러리 설치 없이 비동기 프로그래밍이 가능하게 되었다.

 

이번 글에서는 Python으로 비동기 프로그래밍을 하기 위한 asyncio 라이브러리의 기본 사용법에 대해서 적어둔다.

 

 

asyncio

asyncio 라이브러리는 async, await 구문으로 동시성(concurrent) 프로그래밍을 하기 위한 라이브러리로, 고성능 네트워크 및 웹 서버, 데이터베이스 연결 라이브러리, 분산 작업 큐 등을 제공하는 Python 비동기 프레임워크의 기반으로 사용된다.

 

라이브러리를 사용할 때는 별도 설치 없이 아래와 같이 import 하여 사용할 수 있다.

import asyncio

 

 

async

def 키워드로 선언한 함수는 기본적으로 동기적으로 실행된다. 만약 비동기적으로 실행되는 함수를 선언하고 싶을 때는 def 키워드 앞에 async 키워드를 추가하여 선언한다.

async def hello():
    print('Hello, world!')

Python에서 비동기 함수를 코루틴(Coroutine, Cooperative routine)이라고 하는데, 비동기 함수를 일반 동기 함수 호출하듯이 호출하면 coroutine 객체를 반환한다.

Python에서 코루틴을 선언하는 방법은 여러가지가 있는데, 그중 async def 키워드로 선언한 경우에는 네이티브 코루틴이라고 한다. (코루틴에 대해서는 다른 글에서 추가로 알아보도록 하자…….)

 

 

비동기 함수 실행

선언한 코루틴은 일반 동기 함수를 호출하는 방법으로는 실행할 수 없고, 이벤트 루프나 asyncio.run 함수, await 키워드 등을 통해 실행할 수 있다.

 

이벤트 루프

아래는 이벤트 루프를 얻어서 코루틴을 실행하는 방법이다.

import asyncio
 
async def hello():
    print('Hello, world!')
 
# 코루틴 실행
loop = asyncio.get_event_loop()     # 이벤트 루프를 얻음
loop.run_until_complete(hello())    # hello가 끝날 때까지 기다림
loop.close()                        # 이벤트 루프를 닫음

동작 순서는 다음과 같다.

1. asyncio.get_event_loop로 이벤트 루프를 얻는다.

2. run_until_complete 함수에 네이티브 코루틴을 호출하여 생성된 코루틴 객체를 넣는다.

3. run_until_complete는 코루틴이 이벤트 루프에서 실행되도록 예약한 뒤, 코루틴이 끝날 때까지 기다린다. 이때 이벤트 루프를 통해서 코루틴이 실행된다.

4. 코루틴이 끝나면 이벤트 루프를 닫는다.

 

asyncio.run

아래는 asyncio.run 함수에 코루틴 객체를 넘겨서 실행하는 방법이다.

import asyncio


async def hello():  # async def로 네이티브 코루틴을 만듦
    print('Hello, world!')

asyncio.run(hello())

 

await

일반적으로 비동기 함수는 다른 비동기 함수 내에서 호출된다. 특히 await는 다른 코루틴 내에서만 사용할 수 있는데, 현재 코루틴의 실행을 중단하고 지정한 코루틴이 완료될 때까지 대기했다가 결과를 반환한다.

import asyncio

async def add(a, b):
    print('add: {0} + {1}'.format(a, b))
    await asyncio.sleep(1.0)  # 1초 대기. asyncio.sleep도 네이티브 코루틴
    return a + b

async def print_add(a, b):
    result = await add(a, b)  # await로 다른 네이티브 코루틴 실행하고 반환값을 변수에 저장
    print('print_add: {0} + {1} = {2}'.format(a, b, result))


asyncio.run(print_add(1, 4))

 

 

 

참고 문서

https://docs.python.org/ko/3/library/asyncio.html

https://wikidocs.net/125092

https://dojang.io/mod/page/view.php?id=2469

https://www.daleseo.com/python-asyncio/