이전 1~3편에서 우리는
까지 살펴봤습니다.
이제 Python 3.5에서 등장한 async / await 문법으로 넘어갈 차례입니다.
Python 3.4까지 비동기 코드는 주로 generator 기반 coroutine과
@asyncio.coroutine + yield from 구문을 사용했습니다.
@asyncio.coroutine
def fetch_data():
yield from asyncio.sleep(1)
return "data"
문제점:
yield from 과 일반 generator의 구분이 모호함
yield는 값을 생성하고, yield from은 coroutine 위임을 위해 사용되었습니다.
전혀 다른 목적을 위해 yield 가 사용되고 있는 것입니다.
데코레이터(@asyncio.coroutine) 필수
이 함수가 coroutine인지 generator인지 바로 알기가 어렵습니다
단순 yeild라면 generator고 yeild from 이라면 corutine 입니다.
이를 구분하기 위해서 데코레이터를 필수로 달아줘야 했습니다
불편함
JavaScript, C#, Kotlin 등은 이미 우리에게 익숙한 async/await 형태를 사용하고 있었습니다
PEP 492는 Python 3.5에서 async / await 키워드를 도입하며
기존 @asyncio.coroutine + yield from 방식을 대체했습니다.
PEP492의 abstraction을 봅시다
인터넷과 네트워크 환경이 발전함에 따라 반응성이 높고 확장성 있는 코드를 작성해야 할 필요성이 커지고 있습니다.
이 PEP의 목표는 Python에서 비동기(asynchronous)와 동시성(concurrent) 코드를 보다 쉽고, 더 Pythonic하게 작성할 수 있도록 하는 것입니다.
이를 위해 coroutine을 Python의 독립적인 핵심 개념으로 격상시키고, 이를 지원하는 새로운 문법을 도입합니다.
최종적으로는 비동기 프로그래밍을 위한 공통적이면서도 이해하기 쉬운 사고 체계를 마련하고, 그 사용 경험을 가능한 한 동기(synchronous) 프로그래밍과 유사하게 만드는 것을 지향합니다.
abstract를 보면 async/await 키워드의 목적을 잘 알 수 있습니다.
비동기와 동시성 코드를 보다 쉽고, 더 pythonic 작성할 수 있게 한다
이를 위해서, 아래 내용을 제안하는 군요
"coroutine을 python의 독립적인 핵심 개념으로 격상하고, 이를 지원하는 문법을 도입한다"
그러면 pep492에서 제안한 문법이 뭔지 볼까요?
import asyncio
@asyncio.coroutine
def old_style():
yield from asyncio.sleep(1)
return "done"
loop = asyncio.get_event_loop()
result = loop.run_until_complete(old_style())
print(result)
import asyncio
async def new_style():
await asyncio.sleep(1)
return "done"
result = asyncio.run(new_style())
print(result)
차이점
@asyncio.coroutine → async defyield from → awaitasync def hello():
return "Hello Async"
print(hello()) # <coroutine object hello at 0x...>
async def로 정의된 함수는 즉시 실행되지 않고 coroutine 객체를 반환import asyncio
async def say_hello():
await asyncio.sleep(1)
print("Hello World")
asyncio.run(say_hello())
import asyncio
async def worker(name):
print(f"{name} 시작")
await asyncio.sleep(1)
print(f"{name} 완료")
async def main():
await asyncio.gather(
worker("작업1"),
worker("작업2")
)
asyncio.run(main())
출력 예시
작업1 시작
작업2 시작
작업1 완료
작업2 완료
async/await는 단순히 쓰기 편한 문법이 아니라, 비동기 코드의 가독성과 명확성을 높이는 언어 차원의 개선이였습니다
다음 5편에서는 async/await가 실제로 동작하는 기반인 이벤트 루프(Event Loop) 구조를 깊이 살펴보겠습니다.