🚨 더 구체적인 내용은 아래 링크에 아주 친절하게 잘 정리되어 있으니 꼭 링크가서 읽어주세요!!
https://it-eldorado.tistory.com/159?category=749661
asyncio를 이해하기 전, 코루틴에 대해 먼저 알아두어야 한다.
코루틴은 서브루틴과 달리 현재 상태값을 저장하고 메인루틴으로 돌아간 뒤 나중에 호출하게 되면 저장했던 상태를 꺼내서 다음 상태를 진행해주는 것을 의미한다.
일반적인 함수를 서브루틴이라고 부르는데 이는 return을 통해 메인루틴으로 영원히 돌아가며 다시 서브루틴으로 돌아올 수 없다는 것에서 차이점이 있다.
그러면, 코루틴은 어떻게 작성되는걸까? → async를 def앞에 붙여주면 된다. async def
코루틴은 비동기 함수라고 부른다. 비동기란 어떤 작업을 기다리지 않고 그 시간동안 다음 작업을 진행하는 것을 의미한다. python은 동기로 작성된 언어라 나중에 추가된 코루틴이라는 개념은 비동기 코드를 작성할 수 있게 한다.
본격적으로 async로 들어가기 전, 알아두어야 할 개념이 또있다(…!!)
바로 제너레이터인데, 앞에서 말한 코루틴이 이 제너레이터를 기반으로 구현이 되어있다. 즉, 코루틴은 제너레이터 인 것이다.
왜 제너레이터를 이용하였을까? → yield 키워드를 breakpoint로 삼아 실행이 중단되고 재개될 수 있는 특징을 가지고 있기 때문이다.
파이썬 3.5 버전 이하에서는 코루틴을 작성하기 위해서는 제너레이터를 기반으로 작성해야 했다. 하지만 async라는 개념이 나오고 나서부터는 코루틴을 쉽게 작성할 수 있게되었음.
async
는 거창한 것이 아니라 코루틴이자 제너레이터이며 비동기 함수를 작성하기 위한 문법이다.
그러면 async def 즉 비동기 함수는 무엇을 반환할까?
→ “코루틴”객체를 반환한다.
async def coroutine():
print('coroutine')
coroutine()
# 출력 : <coroutine object async_func at 0x015A9540>
# 주의 : 'coroutine'이 출력되지는 않음(코루틴이 실행되진 않음).
이제 우리는 async
는 비동기 함수인 코루틴을 만들기 위한 키워드인 것 까지 알게되었다. 그러면 async
와 같이 다니는 짝꿍인 await
는 무엇일까?
바로
또 다른 코루틴을 실행하기 위한 키워드
이다.
이렇게만 보면 무슨말인지 모르겠으니 코드를 살펴보자.
import asyncio, time
async def greeting(delay, print_string):
await asyncio.sleep(delay)
print(print_string)
async def main():
print(f'시작 시간 -> {time.ctime()}')
await greeting(1, 'Hello!') # 2
await greeting(2, 'World!') # 2
print(f'끝난 시간 -> {time.ctime()}')
asyncio.run(main()) # 1
# 결과
시작 시간 -> 22:45:32
hello
world
끝난 시간 -> 22:45:35
# 실행시간은 총 3초가 걸린 것을 확인할 수 있다. 왜일까?
asyncio.run(main())
: asyncio 모듈에서 제공하는 run()함수로 async def
함수, 즉 비동기 함수를 실행하게 된다.await
를 통해 새로운 코루틴인 greeting
을 실행한다.잠깐! 🤚
async는 비동기 함수라고 배웠다. 그러면, Hello!를 출력하는 greeting을 실행함과 동시에 World!를 출력하는 greeting을 실행할 것 같지 않은가? 그러면 2초가 걸려야하는데, 생각했던 것과 달리 3초가 걸린 것을 확인할 수 있을 것이다.
나중에 작성하겠지만, create_task
(혹은 ensure_future
) 를 사용하지 않고 run만 해주게 된다면 코루틴 객체만 리턴한다.
반면 create_task
는 코루틴 객체를 가지고 비동기 작업 객체인 Task
를 만들고 실행한다.
즉 위에 있는 코드는 앙꼬없는 찐빵 초코없는 초코칩 쿠키인 셈! 비동기 함수를 작성하긴 했으나 비동기적으로 사용하지 못하고 있는 상태인 것이다!
yield from
키워드와 유사하다.__await()__
메서드가 구현된 Awaitable한 객체를 넣어주면 된다.__await()__
메서드를 호출하여 제너레이터 객체를 얻고, 이를 통해 해당 제너레이터를 실행하는 방식으로 동작한다.다음 게시글에서는 Future, Task에 대해 정리해보겠다.