이전 글에서는 Python의 코루틴, Async/await 용어 등에 대해 이해해보았다. (개념과 설명에 대한 이해는 이전글 참조)
https://yubi5050.tistory.com/234
이번 글에서는 Python 코루틴 구현을 위한 Generator와 asyncio 라이브러리의 async/await 구문을 구현 및 비교해본다.
코드 예제 - Generator
generator는 yield 구문을 이용해 class generator 방식의 코루틴이 동작 된다.
next로 generator 객체를 호출시 yield의 값들이 반환되며, 설정된 iterator의 갯수가 초과되면 Stopiteration이 발생한다.
Generator를 이용한 Coroutine
- yield 상태가 되어, 실행이 일시 정지 되어 있는 generator에 값을 전달하여 실행하고 결과를 받음
# generator_ex1.py
def test1():
print('print 1')
yield 1
print('print 2')
yield 2
def test2():
for i in range(10):
yield i * 2
if __name__ == "__main__":
# case 1
gen1 = test1()
print(type(gen1)) # class 'generator'
print('=== ', next(gen1))
print('=== ', next(gen1))
print()
# case 2
gen2 = test2()
print(type(gen2)) # class 'generator'
for _ in range(10+1):
print(next(gen2), end = ' ') # stop iteration 에러 발생
코드 예제 - async/await
awyncio 라이브러리의 async/await 구문을 이용해 코루틴을 작성한다.
단순 await를 사용했을 때와 태스크 오브젝트를 생성하는 create_task 방식으로 나누어서 비교해본다.
- main1() : await 만 단순 사용하며 say_after(1), say_after(2)가 순차적으로 실행 => 총 3초가 소요됨
- main2() : create_task()로 task object를 만들어 say_after(1), say_after(2) 동시에 실행 => 총 2초가 소요됨
- asyncio.run() 함수 : 현재의 스레드에 event_loop를 설정해, 넘어오는 Coroutine 객체들을 Task로 만들어 실행하고, 해당 Task가 완료되면 event_loop를 해지
import asyncio
import time
# await asyncio.sleep(1) # await : 기다리게 하기.
async def say_after(delay):
await asyncio.sleep(delay)
# 1. create_task 사용 없이 실행 - 순차 실행 : 3초 소요
async def main1():
print(f"1. started at {time.strftime('%X')}")
await say_after(1)
await say_after(2)
print(f"1. finished at {time.strftime('%X')}")
# 2. create_task로 만들고 동시에 실행 - 동시 실행 : 2초 소요
async def main2():
task1 = asyncio.create_task(
say_after(1))
task2 = asyncio.create_task(
say_after(2))
print(f"2. started at {time.strftime('%X')}")
await task1
await task2
print(f"2. finished at {time.strftime('%X')}")
if __name__ == "__main__":
print('=== main1 test ===')
asyncio.run(main1())
print('=== main2 test ===')
asyncio.run(main2())
async/await의 event loop 플로우
최초 sync 함수(위 코드에선 실제 .py의 main 함수) 에서 run()을 통해 event_loop를 활성화하고, 실행되는 코루틴 객체들을 병렬적으로 실행하고, 완료되면 event_loop를 닫는다.
asyncio 라이브러리를 통해 coroutine을 구현시 아래 두 경우는 같은 역할을 수행한다.
asyncio.run()
loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine_method())
loop.close()
참고 문헌
- https://it-eldorado.tistory.com/159 // 비동기 프로그래밍 동작 원리 (asyncio)
- https://docs.python.org/ko/3/library/asyncio.html // Docs - asyncio 비동기 I/O
'Python > Advanced' 카테고리의 다른 글
[Python] 가상환경, 패키지 관리 모듈 정리 (pyenv, pipenv, poetry, venv) (0) | 2023.02.11 |
---|---|
[Python 비동기] (3) Library, Framework 특징 비교 (0) | 2023.02.09 |
[Python 비동기] (1) 코루틴, 비동기 관련 용어 이해 (0) | 2023.02.08 |
[Pytest] 4. Pytest with Django (Feat. pytest-Django) (0) | 2022.11.06 |
[Pytest] 3. Pytest 문법 (Feat. fixture, parametize) (0) | 2022.11.06 |