검색하기귀찮아서만든블로그

[python] coroutine 비동기 처리 본문

개발

[python] coroutine 비동기 처리

hellworld 2022. 6. 6. 07:57

프로그램을 작성할 때 IO (통신)가 발생하면 대기 시간이 많아 시리얼라이즈한 프로그램은 유연한 처리가 어려워진다. 이때 비동기 처리를 통해서 통신 대기시간 동안 다른 작업이 가능하도록 처리하곤 한다.

c++ 에서 비동기 처리를 하기 위해 스레드를 사용하면 동기화 처리를 고려해야 한다. Python 3.5, Go, 코틀린, javascript, c# 2.0, c++ 20 등 에서 coroutine 을 지원한다. coroutine 은 별도의 스레드를 생성하는 것이 아니라 단일 스레드의 스케줄링을 통해서  스레드 동기화 처리 없이 간단하게 비동기 처리를 할 수 있도록 강력한 기능을 제공한다. 

python 3.5부터 async, await 키워드를 기본으로 제공하는데 함수 앞에 async 키워드를 붙이고 호출할 때 asyncio.run 를 사용해서 호출하면 간단하게 비동기 처리가 가능하다. 비동기 함수 내에서 다른 비동기 함수를 호출할 경우 await 키워드를 사용하면 된다.

아래 예시는 비동기 함수 내에서 비동기 / 동기 waitable 함수를 호출하는 테스트 코드이다. 두 케이스 모두 3초, 2초, 1초 총 6초가 소요되는 동작을 수행하지만 최종 처리 시간은 Async 로 호출한 경우 3초가 소요된다. 이와 같이 Async 호출은 별도의 스레드를 사용하지 않고 동시에 처리가 가능하다.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
import asyncio

def Sync_sleep(nWaitTime):
    time.sleep(nWaitTime)

async def Async_sleep(nWaitTime):
    await asyncio.sleep(nWaitTime)

# 비동기 함수 
# Param [in] bUseAsyncIo
#  - True : 비동기 함수 처리를 대기한다.
#  - False : 동기 함수를 호출한다.
async def async_func(bUseAsyncIo):
    if bUseAsyncIo:
        # 아래 비동기 함수가 모두 완료 될 때까지 대기한다. (3초)
        await asyncio.wait([Async_sleep(3), Async_sleep(2), Async_sleep(1)])
    else:
        Sync_sleep(3)
        Sync_sleep(2)
        Sync_sleep(1)

#비동기 함수 내에서 비동기 함수 처리 대기.
tmPrev = time.time()
asyncio.run(async_func(True))
print('1. asyncio.run(async_func(True)) {0} sec\n'.format(time.time() - tmPrev))

# 비동기 함수 내에서 동기 함수 호출
tmPrev = time.time()
asyncio.run(async_func(False))
print('2. asyncio.run(async_func(False)) {0} sec\n'.format(time.time() - tmPrev))
(env) PS D:\project\python>  d:; cd 'd:\project\python'; & 'd:\project\python\Coroutine\env\Scripts\python.exe' 'c:\Users\ymkang\.vscode\extensions\ms-python.python-2022.6.3\pythonFiles\lib\python\debugpy\launcher' '63425' '--' 'd:\project\python\Coroutine\CoroutineTest.py' 
1. asyncio.run(async_func(True)) 3.0266263484954834 sec

2. asyncio.run(async_func(False)) 6.0239105224609375 sec