이전 글 마지막 코드를 보면 비동기 함수를 만들었지만 비동기적으로 실행되지 않았다.
이번 글에서는 앙꼬있는 찐빵, 초코있는 초코칩 쿠키를 만들어보겠다.
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())
위 코드는 async
와 await
를 이용해서 뭔가 비동기적인 코드를 만든 것 같지만, 까보면 그렇지 않다.
# 결과
시작 시간 -> 22:45:32
hello
world
끝난 시간 -> 22:45:35
위 함수를 실행해보면 결과값이 3초가 나오는 것을 확인할 수 있을 것이다.
왜일까?
이유는 비동기 작업 객체를 만들어주지 않았다.
async
와 await
만을 이용해서는 비동기적인 동작을 하지 않는다. Task
나 Future
를 이용해서 "비동기 작업객체"를 만들고 그걸 실행해야 비동기적인 코드를 실행할 수 있다.
그럼 진짜로 비동기적인 코드를 만들어보자.
아래 코드는 비동기적으로 동작하지 않는다.
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()}')
loop = asyncio.get_event_loop()
task = loop.create_task(main())
loop.run_until_complete(task)
pending = asyncio.all_tasks(loop=loop)
for task in pending:
task.cancel()
group = asyncio.gather(*pending, return_exceptions=True)
loop.run_until_complete(group)
loop.close()
나는 main 함수만 create_task
를 이용하여 비동기 객체로 만들어주면 내부에 있는 greeting
함수는 알아서 비동기적으로 실행될 것이라고 생각했다.
하지만 아니었다.
await
는 뒤에 적혀져 있는 비동기 함수가 끝날 때까지 기다려주는 키워드로 동기로 실행되든 비동기로 실행되든 관심이 없다.
그러면 아래쪽에서 task = loop.create_task(main())
이부분을 통해서 비동기적으로 실행되지 않을까?
👉 main만 비동기객체가 된 것이고, 우리가 가장 중요하게 봐야 할 greeting은 비동기 객체로 만들어지지 않았다.
그렇다면 어떻게 해야할까?
greeting을 비동기 객체로 만들어주면 된다!
import asyncio, time
async def greeting(delay, print_string):
await asyncio.sleep(delay)
print(print_string)
# 앙꼬없는 찐빵을 앙꼬있는 찐빵으로 만들기 (진짜 비동기 작업객체를 만들어보자!)
async def main():
print(f'시작 시간 -> {time.ctime()}')
task1 = loop.create_task(greeting(1, 'Hello!'))
task2 = loop.create_task(greeting(2, 'World!'))
await task1
await task2
print(f'끝난 시간 -> {time.ctime()}')
loop = asyncio.new_event_loop()
task = loop.create_task(main())
loop.run_until_complete(task)
loop.close()
여기서는 greeting 함수를 모두 "task"로 만들어주었고 만들어준 task를 await하게 만들어서 비동기객체가 끝날 때 까지 기다리게 만들어주었다.
시작 시간 -> 14:21:31
Hello!
World!
끝난 시간 -> 14:21:33
그러면 이렇게 실행시간이 2초로 줄어든 것을 확인할 수 있다.
"비동기로 동작하고 싶은 객체"를
task(future)
로 만들어준다.