Python 동기(Synchronous)와 비동기(Asynchronous) (2)
이번 포스팅은 인프런 강좌인
파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI)에서 배운 내용을 기반으로 정리한 것입니다.
이전 포스팅에서 동기와 비동기에 대해 간략하게 살펴봤고, 이번 포스팅에서는 asyncio 라이브러리의 사용법과 그 활용에 대해 보겠습니다.
asyncio 라이브러리
aysncio 공식 문서는 여기에서 확인하세요.
공식문서에 따르면, asnycio 라이브러리는 asyncio는 async/await 구문
을 사용하여 동시성 코드를 작성하는 라이브러리입니다.
여기서 동시성이라는 것은 무엇일까요?
동시성
동시성이란, concurrency
를 의미하는데, 이는 여러 작업들이 스위치되면서 작동하는 것을 의미합니다.
즉, 싱글코어에서 멀티스레드가 작동하는 것을 동시성
이라고 하고, 이와 대비되는 개념으로 병렬성(parallel)
이 있습니다.
병렬성은 멀티코어에서 멀티스레드를 동작시키는 것
을 의미합니다.
아래의 간단한 이미지로 두 차이점에 대해서 더 알아보겠습니다.
3개의 Task가 주어졌다고 했을 때, 병렬성은 멀티코어에서 각각의 Task를 맡아서 처리합니다.
반면, 동시성의 경우 하나의 코어에서 Context Switch가 반복적으로 일어나면서
특정 Task를 처리하다가 다른 Task로 넘어가고 다시 돌아오면서 주어진 Task들을 해결합니다.
이러한 동시성 코드를 작성하도록 돕는 것이 asycio이며 이는 결국 비동기적 프로그래밍(코드가 작성된 순서대로 작동하지 않는 것) 을 구현해주는 것이라고도 할 수 있습니다.
asyncio와 코루틴
asyncio에서 async/await 문법
으로 선언된 코루틴
이 기본적인 작성 방법입니다.
여기서 코루틴이란, 여러 진입점과 여러 탈출점
이 존재하는 서브루틴의 더 일반화된 형태입니다.
일반적인 서브루틴은 진입점과 탈출점이 하나인 반면, 코루틴은 다양하기 때문에 동시성 작업이 수행될 수 있도록 합니다.
코루틴 함수
공식문서에 따르면, 코루틴 함수란, 코루틴 객체를 돌려주는 함수
입니다.
코루틴 함수는 async def 문으로 정의될 수 있고, await 와 async for와 async with 키워드를 포함할 수 있습니다.
asycio 문법
asyncio 문법은 다양하게 있지만, 그 중에서도 어웨이터블
과 .gather
에 대해서 알아보겠습니다.
import asyncio
async def main():
print('hello')
await asyncio.sleep(1)
print('world')
>>> asyncio.run(main())
hello
world
우선 asyncio를 import 시킨 후, def 앞에 async
를 선언해주고, await
를 사용하여
어웨이터블 객체를 만들어줍니다.
위의 예제에서 await asyncio.sleep(1)
이라는 코드로 인해 hello와 world 사이에 1초의 딜레이가 있습니다.
또한 asyncio에서는 함수를 실행할 때, 최상위 진입점인 main
을 실행하는 asyncio.run()
함수로 실행합니다.
어웨이터블 객체란, 코루틴, 태스크, 퓨처 총 3가지 주요 유형이 있습니다. 각각의 유형에 대해서는 공식문서를 한 번 읽어보세요.
예제코드
그렇다면, 이전 포스팅에서 다룬 음식 배달 코드를 다시 한 번 살펴보겠습니다.
import time
import asyncio
async def delivery(name, mealtime):
print(f"{name}에게 배달 완료!")
await asyncio.sleep(mealtime)
print(f"{name} 식사 완료, {mealtime}시간 소요...")
print(f"{name} 그릇 수거 완료")
return mealtime
async def main():
result = await asyncio.gather(
delivery("A", 1),
delivery("B", 2),
delivery("C", 3),
)
print(result)
if __name__ == "__main__":
start = time.time()
asyncio.run(main())
end = time.time()
print(end - start)
async def
를 통해 각각의 코루틴을 선언해주고, 중간에 어웨이터블한 객체를 만들어줍니다.
여기서 await asyncio.gather(*aws)
의 사용을 주의해야합니다. 이 코드는 aws
에 있는 여러 어웨이터블 객체를 동시에 실행합니다.
result = await asyncio.gather(
delivery("A", 1),
delivery("B", 2),
delivery("C", 3),
)
을 보면, gather안에 앞에서 정의한 delivery
함수가 들어가있기 때문에 A,B,C에 대해서 동시에 실행해줍니다.
따라서 결과적으로, 1초 2초 3초를 각각 기다리는 것이 아니라 3초안에 3개의 Task가 모두 수행됩니다.
다음 포스팅에서는 asyncio와 같이 비동기 프로그래밍을 구현할 수 있는 다른 라이브러리를 살펴보고, 같이 활용하는 방법에 대해 알아보겠습니다.
Keep Steady & Do not give up
댓글남기기