[etc] 동기(Synchronous)와 비동기(Asynchronous)
이번에 Tornado 웹프레임워크를 알게되었는데, 해당 웹프레임워크는 비동기 네트워킹을 지원하는 것이 주요 특징이다. 토네이도의 동작 방식을 이해하기 전 동기와 비동기에 대해서 조금 자세히 알아보고자 한다.
프로그래밍에서 동기(Synchronous)와 비동기(Asynchronous)는 작업 처리 방식의 두 가지 주요 패턴이다.
동기(Synchronous)
"순서대로" 처리되는 방식이다.
말그래도 한 작업이 완료되어야 다음 작업이 시작된다.
예를 들어, 버스가 한 곳에 정차하면 승객이 모두 타고 내린 후에야 출발한다. 승객이 다 탑승할 때까지 기다려야하기 때문이다.
동기 방식은 코드가 간단하고 이해하기 쉬우며, 디버깅이 용이하지만 (문제가 발생한 위치를 쉽게 찾을 수 있음)
긴 작업이 있을 경우 전체 프로그램이 멈추게 된다는 단점이 있다.
import time
def sync_task():
print("작업 A 시작")
time.sleep(2) # 2초 동안 대기 (긴 작업 시뮬레이션)
print("작업 A 완료")
print("작업 B 시작")
time.sleep(2) # 2초 동안 대기
print("작업 B 완료")
sync_task()
작업 A가 완료되고 작업 B가 시작되므로, 총 대기 시간은 4초가 된다.
비동기(Asynchronous)
비동기는 "동시에" 처리되는 방식이다.
하나의 작업이 진행되는 동안 다른 작업을 수행할 수 있다.
예를 들어, 레스토랑에서 손님이 음식을 주문하면 주방에서 음식을 준비하는 동안은 손님은 다른 일을 하거나 대화를 나눌 수 있으며 음식이 준비되면 알림을 받는다.
비동기 방식은 여러 작업을 동시에 처리할 수 있어 효율적이지만, 여러 작업이 동시에 진행되므로 관리가 어렵고 어떤 작업에서 문제가 발생했는지 파악하기 힘들다는 단점이 있다.
파이썬에서 비동기는 asyncio 라이브러리를 사용해서 구현할 수 있다.
import asyncio
async def async_task():
print("작업 A 시작")
await asyncio.sleep(2) # 2초 동안 대기 (긴 작업 시뮬레이션)
print("작업 A 완료")
print("작업 B 시작")
await asyncio.sleep(1) # 1초 동안 대기
print("작업 B 완료")
async def main():
await asyncio.gather(async_task(), async_task()) # 두 개의 비동기 작업을 동시에 실행
asyncio.run(main())
async.def로 비동기 함수를 정의하고, await을 사용하여 비동기 작업을 기다린다.
async.gather()를 통해 두 개의 비동기 작업을 동시에 실행할 수 있다. 작업 A와 B가 동시에 진행되므로, 총 대기 시간은 2초가 된다.
결론
정리해보면 동기(Synchronous)는 순차적으로 작업을 하기 때문에, 짧고 간단한 작업을 수행하거나 데이터를 순차적으로 처리해야 할 때 유용하다.
비동기(Asynchronous)는 동시에 작업을 진행하기 때문에, 웹 서버에서 많은 클라이언트 요청을 동시에 처리할 때 유용하다. 외부 API와 통신할 때 응답을 기다리는 동안 다른 작업을 수행할 수 있다.