𝑷𝒓𝒐𝒈𝒓𝒂𝒎𝒎𝒊𝒏𝒈/𝐶𝑆

동기와 비동기, 블로킹과 논블로킹

기누 2022. 11. 30. 01:08

얼마전에 SingleTon 패턴을 정리하면서, 쓰레드를 이용한 적이 있다. 쓰레드에 대한 정리는 이전에 했었는데, 오늘은 이 쓰레드의 바탕이 되는 동기, 그리고 비동기와 많이 혼동되는 개념인 블록(Block) 과 논블록(Non-Block)에 대해서도 간단히  알아보자! 

 

이미지 출처 : https://evan-moon.github.io/2019/09/19/sync-async-blocking-non-blocking/

데이터를 받는 방식에는 동기식 처리와, 비동기식 처리라는 두가지의 방식이 있다. 

 

동기 (Synchronous) 

Synchronous 의 사전적 뜻은 다음과 같다 : happening, existing, or arising at precisely the same time. 무슨 말인가 하면, 정확히 같은 시간에 발생, 존재하는 것이다. 즉, 동시에 일어난다는 것이다. 

 

많은 포스팅에서는 동기를 '데이터의 요청과 결과가 한 자리에서 동시에 일어나는 것'이라고 말한다. 또한, 요청을 하면 시간이 얼마가 걸리던 요청한 자리에서 결과가 주어져야 한다고 한다.

 

하지만 요청과 응답이 동시에 일어나는 게 가능할까? 무언가 모순처럼 느껴졌다. 여러 포스팅을 찾아보며 고민하던 중, 요청과 응답의 동시성을 '현재 작업의 응답다음 작업의 요청'이라고 정의한 포스팅을 읽었다. 해당 글의 글쓴이는 동기 방식을 현재 작업의 응답과 다음 작업 요청의 '타이밍'을 맞추는 방식이라고 소개하는데, 이해하기에 더욱 수월했다. 

 

물론 쓰레드 포스팅에서 알아봤던 것 처럼, 프로그래밍에서의 작업은 굉장히 빠른 속도로 일어나기 때문에, 요청이 동시에 들어갈 경우 순서대로 일어나지 않을 수 있다. 이때문에 요청과 응답이 동시에 일어난다고 여겨지는 것 같다. 

이러한 동기의 장점은 설계가 매우 간단하고 직관적이라는 점이 있다. 하지만 결과가 주어질 때까지 아무것도 못하고 대기해야 한다. 

비동기 (Asynchronous) 

반면, 비동기는 동시에 일어나지 않는다는 뜻으로, 요청과 결과가 동시에 일어나지 않는 것이다. 즉, 동기와는 반대로 현재 작업의 응답과 다음 작업의 요청이 일치하지 않는다. 

 

동기 방식은 프로세스가 작업을 시작할 때 이전에 진행중인 프로세스의 작업 종료 시점을 알아야한다. 하지만 비동기 방식에서 하위 프로세스는 상위 프로세스가 진행중이든 종료되었든은 중요하지 않다. 즉, 노드 사이의 작업 처리 단위를 동시에 맞추지 않아도 된다. 

비동기는 결과가 주어지는데 시간이 걸리더라도 다른 작업을 할 수 있으므로 자원들을 효율적으로 사용할 수 있다. 하지만 동기보다 복잡한 설계를 필요로 한다. 

 

비동기는 주로 다음과 같은 작업들을 처리할 때 사용된다

  • Ajax Web API 요청 : 서버쪽에서 데이터를 받아와야 할 때는 요청을 하고 서버에서 응답을 할 때 까지 대기해야 하기 때문 
  • 파일 읽기 : 서버 쪽에서 파일을 읽는 상황을 위해서 비동기 처리 
  • 암호화 / 복호화 : 암호화 복호화 작업 시 바로 처리가 되지 않고 어느정도 시간이 걸리는 경우가 있기 때문에 비동기 처리 
  • 작업 예약 : 어떤 작업을 몇 초 후 동작해야하는 경우 setTimeout 을 사용해 비동기 처리 

 

동기 방식에 대한 개념을 이미지로 표현하면 다음과 같다.

 

이미지 출처 : https://learnjs.vlpt.us/async/

블록 (Block)과 논블록 (Non-Block)

블록과 동기, 논블록과 비동기는 같은 개념으로 많이 혼동되는데, 동기와 비동기는 프로세스 수행 순서 보장에 대한 매커니즘이고 블록킹과 논블록킹은 프로세스의 유휴(쓰지 않고 놀림) 상태에 대한 개념으로 완전한 별개의 개념이다.

하지만 실제로 구현체에서 두개의 개념은 함께 조합하여 사용된다.

 

블로킹과 논블로킹은 하나의 작업이, 전체적인 흐름을 막느냐 안막느냐에 대한 관점이다. 즉, '제어권이 누구에게 있느냐'가 중요하다.

Blocking : 자신의 작업을 진행하다가 다른 주체의 작업이 시작되면,
                  다른 작업이 끝날 때까지 기다렸다가 자신의 작업을 시작하는 것
Non-Blocking : 다른 주체의 작업에 관련없이 자신의 작업을 하는 것

블로킹 

블로킹은 A함수가 B함수를 호출하면, 제어권을 A가 호출한 B 함수에게 넘겨준다

  1. A함수가 B함수를 호출하면 B에게 제어권을 넘긴다.
  2. 제어권을 넘겨받은 B는 열심히 함수를 실행한다. A는 B에게 제어권을 넘겨주었기 때문에 함수 실행을 잠시 멈춘다.
  3. B함수는 실행이 끝나면 자신을 호출한 A에게 제어권을 돌려준다.

함수 A는 함수 B의 리턴값을 필요로 한다(동기). 그래서 제어권을 함수 B에게 넘겨주고, 함수 B가 실행을 완료하여 리턴값과 제어권을 돌려줄때까지 기다린다(블로킹).

 

예를들어 브라우저(크롬)가 실행(요청)되는 시간이 10분이라고 가정했을 때, 브라우저(크롬)가 오픈(결과) 되기 전 까지 다른 브라우저(사파리, 익스플로러 등)는 실행되지 못하고 계속 대기해야 하는 상태블록 상태 라고 한다.

이때 동기 방식이기 때문에 크롬이 끝난 후 다른 브라우저가 실행된다는 '순차적인 작업의 진행이 보장'되는 것이고, 블로킹 방식이기 때문에 '어떠한 작업이 진행 중일 때는, 다른 작업을 동시에 진행할 수 없는 것'이다.  

논블로킹 

반대로 논블로킹은 A함수가 B함수를 호출해도, 제어권은 그대로 자신이 가지고 있는 것이다. 

  1. A함수가 B함수를 호출하면, B 함수는 실행되지만, 제어권은 A 함수가 그대로 가지고 있는다.
  2. A함수는 계속 제어권을 가지고 있기 때문에 B함수를 호출한 이후에도 자신의 코드를 계속 실행한다.

 A 함수는 B 함수를 호출한다. 이 때 제어권을 B 함수에 주지 않고, 자신이 계속 가지고 있는다(논블로킹). 따라서 B 함수를 호출한 이후에도 멈추지 않고 자신의 코드를 계속 실행한다. 그리고 B 함수를 호출할 때 콜백함수를 함께 준다. B 함수는 자신의 작업이 끝나면 A 함수가 준 콜백 함수를 실행한다(비동기).

 

브라우저(크롬)가 실행(요청)되는 시간이 10분이라고 가정했을 때, 브라우저(크롬)가 오픈(결과) 되기 전 까지 다른 브라우저(사파리, 익스플로러 등)는 대기 없이 자유롭게 사용가능한 상태논블록 상태라고 한다. 

비동기 방식이기 때문에 '상위 프로세스는 하위 프로세스의 작업 완료 여부를 신경쓰지 않는 것'이고, 논블로킹 방식이기 때문에 상위 프로세스는 하위 프로세스와 '동시에 작업을 계속 수행할 수 있는 상태'이다.  

 

 


오늘은 이렇게 동기와 비동기, 그리고 간단하게 블록과 논블록에 대해서도 정리해봤다. 코딩할 때 오늘 정리한 내용을 신경쓰도록 하자 :) !

 

 

[참고]

https://evan-moon.github.io/2019/09/19/sync-async-blocking-non-blocking/

https://velog.io/@dev_hyemi/%EB%8F%99%EA%B8%B0-%EB%B9%84%EB%8F%99%EA%B8%B0

https://velog.io/@nittre/%EB%B8%94%EB%A1%9C%ED%82%B9-Vs.-%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9-%EB%8F%99%EA%B8%B0-Vs.-%EB%B9%84%EB%8F%99%EA%B8%B0