나만의 작은 도서관

[Network] 블로킹/논블로킹 방식, 동기/비동기 방식 본문

Common/CS-네트워크

[Network] 블로킹/논블로킹 방식, 동기/비동기 방식

pledge24 2025. 1. 11. 02:01
주의사항: 해당 글은 개인적인 이해를 위해 작성된 글이며, 잘못된 정보가 포함되어 있을 수도 있습니다.

목차

  • 블로킹(Blocking) 방식과 논블로킹(Non-Blocking) 방식
    • 블로킹(Blocking) 방식과 논블로킹(Non-Blocking) 방식
    • 블로킹/논블로킹 동작 방식
    • 블로킹/논블로킹 방식의 문제
  • 동기(Synchronous) 방식과 비동기(Asynchronous) 방식
    • 동기(Synchronous) 방식과 비동기(Asynchronous) 방식
    • 동기/비동기 동작 방식
    • 비동기 방식의 사용이 멀티쓰레드 환경임을 의미하지는 않는다.
  • 두 방식의 조합
    • 동기-블로킹 방식
    • 동기-논블로킹 방식
    • 비동기-블로킹 방식
    • 비동기-논블로킹 방식
  • 참고 자료

블로킹(Blocking) 방식과 논블로킹(Non-Blocking) 방식

 

블로킹(Blocking) 방식과 논블로킹(Non-Blocking) 방식

작업을 요청했을 때 해당 작업이 완료될 때까지 코드 진행을 막는 것을 "블로킹(Blocking)"이라 한다. 따라서, 함수(작업을 의미)를 호출했을 때 다음 코드의 실행을 막는다면 블로킹 방식, 막지 않는다면 논블로킹 방식이라 부른다. 정리하자면 다음과 같다.

  • 블로킹(Blocking) 방식: 작업 요청 시, 해당 작업이 완료될 때까지 다음 코드의 실행을 막는 방식
  • 논블로킹(Non-Blocking) 방식: 작업 요청 시, 해당 작업이 완료될때까지 다음 코드의 실행을 막지 않는 방식. 

블로킹/논블로킹 동작 방식

블로킹 방식(왼쪽), 논블로킹 방식(오른쪽)

 

블로킹 방식이든, 논블로킹 방식이든 상관없이 "제어권"을 넘겨주게된다. 제어권이란 코드를 진행 및 실행할 수 있는 권한을 의미하는데, 제어권을 넘겨주게되면 넘겨준 시점 이후의 코드는 더 이상 진행되지 않는다. 블로킹/논블로킹은 넘겨준 제어권을 돌려받는 시점이 다른데, 위 그림과 같이 블로킹 방식에선 작업이 완료되었을 때 제어권을 돌려받고, 논블로킹 방식에선 요청하자마자 바로 돌려받게 된다.

 

블로킹/논블로킹 방식의 문제

블로킹 방식의 문제점(왼쪽), 논블로킹 방식의 문제점(오른쪽)

 

블로킹 방식과 논블로킹 방식은 각각 서로 다른 문제를 가지고 있다. 

 

블로킹 방식 같은 경우, 블로킹을 걸어두는 동안 다음 작업을 진행할 수 없기 때문에, Task 2처럼 오래 걸리는 작업을 중간에 요청하게 되면, Task 3, Task 4 등과 같은 Task 2 뒤에 있는 작업들이 진행되지 못하고 계속 대기하게 된다. 다르게 표현하자면, Task 2로 인해 전체 대기 시간이 크게 늘어난다.

 

반대로 논블로킹 방식 같은 경우, 오래 걸리는 작업이 있어도 다음 작업을 진행할 수 있기 때문에 블로킹 방식처럼 대기 시간이 늘어나는 문제는 없지만, 해당 작업이 완료되어 리턴한 것이 아니기 때문에 호출 쓰레드는 요청한 작업이 언제 완료되었는지 알 수가 없다.

 

그래서 논블로킹 방식에서 요청한 작업이 완료되었음을 알아내는 방법들이 여러 가지 존재한다. 몇 가지 예시를 들어보자면, 작업이 완료될 때까지 반복 확인하는 방식, 작업이 완료했을 때 상태가 전환하는 신호를 감시하는 이벤트 방식, 작업을 완료했을 때 넘겨받은 콜백 함수수를 호출하는 콜백 방식 등이 있다. 


동기(Synchronous) 방식과 비동기(Asynchronous) 방식

동기(Synchronous) 방식과 비동기(Asynchronous) 방식

동기(Synchronous)는 시간을 맞춰서 작업을 실행한다는 의미를 지닌다. 즉, 일련의 작업을 여러 대상에게 순차적으로 요청할 때, 다음 작업은 현재 작업에 대한 완료 통지를 받는 시간에 맞춰서 다음 작업을 요청한다. 이를 동기/비동기 방식에 적용하여 표현하자면 다음과 같다.

  • 동기(Synchronous) 방식: 요청한 작업에 대한 완료 통지를 받은 후, 다음 작업을 요청한다.
  • 비동기(Asynchronous) 방식: 요청한 작업에 대한 완료 통지와 상관없이 다음 작업을 요청한다.

동기/비동기 동작 방식

모든 작업이 동기인 경우

동기(Synchronous) 방식

  • 요청 쓰레드는 쓰레드 A에게 Task2 작업을 요청한다.
  • 요청을 받은 쓰레드 B는 Task2 작업을 실행한다.
  • 요청 쓰레드는 쓰레드 A에게 완료 통지를 받을 때까지 대기한다.
  • 쓰레드 A가 Task2 작업을 완료했다면 쓰레드 A에게 완료 통지를 보낸다. 
  • Task3, Task4도 위 과정과 동일하게 반복하여 처리한다.

 

모든 작업이 비동기인 경우

비동기(Asynchronous) 방식

  • 요청 쓰레드는 쓰레드 A에게 Task2 작업을 요청한다.
  • 요청을 받은 쓰레드 B는 Task2 작업을 실행한다.
  • 요청 쓰레드는 쓰레드 A의 완료 통지를 기다리지 않고, 쓰레드 B에게 Task3 작업을 요청한다. 동일하게 쓰레드 B의 완료 통지를 기다리지 않고 쓰레드 C에게 Task4 작업을 요청한다.
  • 요청한 작업에 대한 완료 통지가 오면, 완료된 작업에 대한 처리 작업을 진행한다.

 

비동기 방식의 사용이 멀티쓰레드 환경임을 의미하지는 않는다.

비동기 방식으로 요청한 작업을 처리할 쓰레드가 프로세스 외부에 있고, 프로세스 내에 존재하는 메인 쓰레드 1개라면 해당 프로세스는 싱글 쓰레드 환경이라고 부른다. 따라서, 운영체제에 존재하는 쓰레드에게 작업을 요청하는 소켓 I/O나, 프로세스 내부에 이벤트 루프 쓰레드 하나만 남겨놓고 프로세스 외부에 존재하는 백그라운드 쓰레드를 활용하는 Node.js멀티 쓰레드 환경이라 부르지 않는다.

또 다른 케이스로 유니티는 싱글 쓰레드 기반의 환경임에도 불구하고 비동기 방식으로 코루틴을 사용하는데, 이 경우는 게임 루프의 각 프레임마다 코루틴을 겹쳐 실행하는 방식으로 비동기 작업을 처리한다.


두 방식의 조합

동기-블로킹 방식

작업이 완료된 후에 다음 작업을 요청하며(동기), 작업이 완료될때까지 요청한 쓰레드의 코드 진행을 막아놓는 방식(블로킹). 관여된 작업들이 다른 곳에 영향을 주지 않는 경우 적합하다.

 

동기-논블로킹 방식

작업이 완료된 후에 다음 작업을 요청하며(동기), 요청한 쓰레드의 코드 진행을 막아놓지 않는 방식(논블로킹). 현재 작업의 진척도를 확인하거나 이벤트를 감지할 때 사용한다. 사례로 파일 다운로드 진척도 확인, 키보드 키 입력 감지 등이 있다.

 

비동기-블로킹 방식

작업의 완료와 상관없이 다음 작업을 요청하며(비동기), 작업이 완료될때까지 요청한 쓰레드의 코드 진행을 막아놓는 방식(블로킹). 동기-블로킹 방식과 성능 차이가 거의 없으며, 의도적으로 사용할 이유가 딱히 없는 방식이다.

 

비동기-논블로킹 방식

작업의 완료와 상관없이 다음 작업을 요청하며(비동기), 요청한 쓰레드의 코드 진행을 막아놓지 않는 방식(논블로킹). 여러 작업들을 병렬적으로 실행하고 싶을 때 사용한다. 

 


참고 자료

https://youtu.be/EJNBLD3X2yg?si=JyUn3AxGeyCjvSSV

https://youtu.be/mb-QHxVfmcs?si=MXOOvWnK_ZLEnPff

https://inpa.tistory.com/entry/%F0%9F%91%A9%E2%80%8D%F0%9F%92%BB-%EB%8F%99%EA%B8%B0%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%B8%94%EB%A1%9C%ED%82%B9%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC#%EB%B9%84%EB%8F%99%EA%B8%B0%EC%99%80_%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9_%EA%B0%9C%EB%85%90_%EC%B0%A8%EC%9D%B4