Asynchronous Non-blocking 작업

Sync / Async

두 항목을 나누는 기준은 요청한 작업이 진행되는 순서이다. 

Synchronous - 동기: 요청된 작업이 순차적으로 진행된다. 

Asynchronous - 비동기: 요청된 작업 순서가 보장되지 않는다. 

예를 들어, 1, 2, 3번 작업을 순서대로 요청했다고 하자. 동기인 경우는 순서대로 1번, 2번, 3번 작업을 수행하고 결과를 반환한다. 반면 비동기 작업은 1번, 3번, 2번과 같이 다른 순서로 결과를 반환할 수 있다. 

예:

요청 1 → 2 → 3
결과 동기 1, 2, 3
비동기 1, 3, 2 (다른 경우도 가능)

Blocking / Non-Blocking

두 항목을 나누는 기준은 함수의 제어권에 있다. 

Blocking: 함수가 호출되어 제어권을 받은 후 다시 넘겨주지 않는다.

Non-Blocking: 함수가 호출되어 제어권을 받은 후 즉시 넘겨준다.

쉽게 생각해서 자신이 실행되는 동안 다른 함수가 실행되도록 허락하지 않는 상태가 blocking이다. 반면 non-blocking은 호출된 후 제어권을 다시 main 측으로 넘겨준다. 따라서 main 측에서는 다른 작업을 수행할 수 있게 된다. 


Asynchronous Non-blocking Request

아래 글은 Python을 이용해 request 작업을 효율적으로 수행할 수 있는 방법이다. 

 

asyncio 비동기 처리와 장점

Python은 asyncio 라이브러리를 활용해 비동기 실행을 지원한다. 하지만 asyncio의 경우, 파이썬 버전에 따라 많은 변화가 있었다. 아래 글에 포함된 코드는 Python 3.9.12를 활용해 코드를 실행해 보았다.

denev6.tistory.com

위 글의 내용을 짧게 정리하면, 일반적인 방식으로 request 작업을 수행할 때는 7초가 걸렸지만 비동기로 수행할 경우 1초로 단축시킬 수 있다는 것이었다. 위 방법을 sync / async와 blocking / non-blocking 관점에서 다시 분석해 보았다. 

위 그림에서도 볼 수 있듯 request가 먼저 실행되었다고 해서 결과를 먼저 반환하지 않는다. 따라서 async(비동기) 방식이라고 할 수 있다. 또한 main 측에서 제어권을 받아 요청 1을 실행한 후 다른 요청을 보낼 수 있도록 main 측에 제어권을 반납한다. main 측은 요청 2를 실행하고, 위 과정을 계속 반복한다. 제어권을 즉시 주고받으며 main 측에서 다른 작업을 수행할 수 있도록 하는 것으로 보아 request 과정은 non-blocking이다. 

만약 별도의 장치 없이 Python을 이용해 request 작업을 수행하면 Synchronous + Blocking 방식으로 작업하게 된다. 

이 방식은 request를 실행하고 결과 값을 받기까지 대기 시간이 발생한다. 하지만 blocking 상태이기 때문에 main 측에서도 별다른 작업을 하지 못하고 무작정 기다려야 한다. 이 과정에서 시간이 낭비되는 것이다. 

이러한 원리는 I/O 작업에도 동일하게 적용된다. 따라서 Async + Non-blocking을 이용해 I/O 작업을 수행하면 효율적으로 처리할 수 있다. (AIO)


Sync / Async 처리와 Blocking / Non-Blocking에 대한 설명을 찾아보면 IBM Developer - "Boost application performance using asynchronous I/O"에 작성된 이미지가 가장 많이 보인다. 4가지 상황에 대한 예시가 그림으로 잘 정리되어 있어 한 번 읽어보는 것을 추천한다.