Blocking/Non-blocking

ujin·2022년 11월 27일
0

네트워크

목록 보기
9/9

시작하기 전에 블로킹/논블로킹은 동기/비동기와 다르다는 것을 알고 지나가야 한다.

간단하게 비교하면

동기 & 비동기

작업 완료를 누가 신경 쓰는가?

Synchronous : 작업을 동시에 수행하거나, 동시에 끝나거나, 끝나는 동시에 시작. ‘호출한 함수’가 스스로 신경쓴다.

Asynchronous : 시작, 종료가 일치하지 않으며, 끝나는 동시에 시작을 하지 않음, ‘호출된 함수 (callback 함수)’ 가 신경쓰고, ‘호출한 함수’는 신경쓰지 않는다.

블로킹 & 논블로킹

호출되는 함수가 return 되는가? 호출한 함수가 제어권을 넘겨주는가?

✔️ 제어권 : 자신(함수)의 코드를 실행할 권리 같은 것이다. 제어권을 가진 함수는 자신의 코드를 끝까지 실행한 후, 자신을 호출한 함수에게 돌려준다.

Blocking : ‘호출된 함수’가 자신의 작업을 모두 마칠 때까지 ‘호출한 함수’에게 제어권을 넘겨주지 않고 대기한다.

Non-Blocking : ‘호출된 함수’에게 제어권이 넘어가지않고, ‘호출한 함수’가 제어권을 가지고 계속해서 다른 일을 한다.

동기/비동기, 블로킹/논블로킹의 판단 기준은 아래와 같다.

🗣️ 동기/비동기 → 작업완료

블로킹/논블로킹 → 제어권

💡동기/비동기

동기 (Synchronous)

요청과 결과가 동시에 일어난다. 어떤 작업에 대한 요청이 발생했을 때, 그 요청에 대한 응답을 받을 때까지 대기해야 한다. 작업에 대한 완료를 ‘호출한 함수’가 신경을 쓰고 있다.

Thread1, Thread2가 존재할 때 Thread1에서 처리하려고 했던 일을 Thread2에게 보낸 경우, Thread2가 해당 작업을 수행하는 동안 Thread1은 Thread2가 끝날 때까지 대기상태다.


Thread1이 작업1, 작업2, 작업3, 작업4를 가지고 있다.

Thread1이 작업을 Thread2에게 보낸다. Thread1은 Thread2의 작업이 끝난 후부터 2라는 작업을 처리할 수 있다.

비동기 (Asynchronous)

요청과 결과가 동시에 일어나지 않는다. 작업에 대한 완료를 ‘호출 함수’가 아닌 ‘callback’이 신경쓴다.

Thread1, Thread2가 존재할 때 Thread1에서 처리하려고 했던 일을 Thread2에게 보낸 경우, THread2가 해당 작업을 수행하는 동안 Thread1은 대기 없이 나머지 Task2, Task3를 실행한다.

Thread1이 작업1, 작업2, 작업3, 작업4를 가지고 있다.

Thread1이 작업1을 Thread2에게 보낸다. Thread1은 Thread2의 작업의 완료 여부에 상관 없이 계속 실행한다.

💡블로킹/논블로킹

블로킹 (Blocking)

A함수가 실행될 때 제어권이 B함수로 넘어가게 되면 A함수는 제어권이 없는 상태로, B함수의 종료까지 대기 해야한다. 작업은 총 A함수, B함수 2개를 가진 상태이며, 다른 작업을 하는 동안 자신의 작업에 대한 제어권이 없을 때 다른 작업이 끝날 때까지 기다렸다가 자신의 작업을 멈췄던 부분부터 이어나간다.

논블로킹 (Non-Blocking)

A함수가 실행되는 도중에 B함수가 호출되었다. A함수는 제어권을 B함수에 넘기지 않고 그대로 자신이 가지고 있으며 B함수의 완료 여부와 상관없이 작업을 계속 진행한다.

💡조합

동기 (Synchronous) / 블로킹 (Blocking)

동기 (Synchronous) : 호출한 함수가 작업 완료 여부를 확인한다.

블로킹 (Blocking) : 호출된 함수 (task1)이 제어권을 가진다.

Thread1은 Task1이 끝날 때까지 아무것도 하지 못하고 대기해야 한다. 실행, 흐름이 순차적이기 때문에 프로그램을 제어하기 쉽다.

예제코드

모든 인형의 눈알을 다 붙히기 전까지 퇴근은 없다.

상위 프로세스인 boss 함수는 출근 작업을 수행한 뒤 하위 프로세스인 employee 함수에게 인형 눈알 붙히기 작업을 요청하고 있고, 이 인형 눈알 붙히기 작업이 완료되고나서야 boss 함수는 퇴근을 할 수 있다.

쉽게 말해서 작업을 시킨 놈인 상위 프로세스는 작업을 하는 놈인 하위 프로세스가 종료될 때까지 절대 퇴근할 수 없다.

그렇다면 이 예제와 같이 동기적인 작업의 흐름을 유지하면서 employee 함수가 인형의 눈알을 붙히는 동안 boss 함수가 다른 일을 할 수 있을까 ?

동기 (Synchronous) / 논블로킹 (Non-Blocking)

동기 (Synchronous) : 호출한 함수가 작업 완료 여부를 확인한다.

논블로킹 (Non-Blocking) : 호출한 함수가 제어권을 가진다.

물론 할 수 있다.

동기라는 것은 작업들이 순차적인 흐름을 가지고 있다는 것을 의미하기 때문에, 이 전제만 지켜진다면 나머지는 어떤 일이 발생하든 동기 방식이라는 것은 변하지 않는다.

그래서 동기 === 블로킹이라고 말할 수 없다.

Thread1은 task1의 완료 여부에 상관 없이 다른 작업을 진행 할 수 있다. 하지만 task1의 완료 여부를 지속적으로 확인한다.

예제코드

이 예제를 보면 상위 프로세스인 boss 함수는 출근한 후 하위 프로세스인 employee를 호출하여 인형 눈알 붙히기 작업을 시키고 주기적으로 이 작업이 끝났는지 검사하고 있다.

그리고 아직 작업이 끝나지 않았다면 자신 또한 유튜브 시청을 수행한다.

이 코드는 분명히 동기적인 흐름을 가지고 진행하지만 boss 함수 또한 중간중간 작업을 수행하고 있으므로 블로킹이 아니라 논블로킹 방식을 사용하고 있다.

동기 & 블로킹 방식과 마찬가지로 boss 함수는 employee 함수의 작업이 끝나기 전까지는 퇴근을 하지 않는다.

작업의 순서가 지켜지고 있다.

즉, 동기 방식이라는 것은 작업의 순차적인 흐름만 지켜진다면 블로킹이든 논블로킹이든 아무 상관 없다고 할 수 있다.

비동기 (Asynchronous) / 블로킹 (Blocking)

비동기 (Asynchronous) : Callback 함수가 작업 완료 여부를 확인한다.

블로킹 (Blocking) : 호출된 함수 (task1)이 제어권을 가진다.

Thread1이 task1의 작업 완료 여부를 신경쓰지 않으나, 작업이 완료될 때까지 아무것도 하지 못하는 대기 상태이다. 해당 경우는 비동기인데 굳이 블로킹인데, 이는 보통 비동기 + 논블로킹으로 작업을 시도했을 때 잘못된 경우 발생한다.

비동기 (Asynchronous) / 논블로킹 (Non-Blocking)

비동기 (Asynchronous) : Callback 함수가 작업 완료 여부를 확인한다.

논블로킹 (Non-Blocking) : 호출된 함수가 제어권을 가진다.

Thread1이 task1의 완료 여부를 신경쓰지 않고 다른 자신의 작업을 진행한다. 성능과 자원 효율면에서 가장 우수하다.

비동기 방식이기 때문에 상위 프로세스는 하위 프로세스의 작업 완료 여부를 따로 신경쓰지 않는다.

이후 하위 프로세스의 작업이 종료되면 스스로 상위 프로세스에게 보고를 하든 아니면 다른 프로세스에게 일을 맡기든 할 것이다.

그리고 논블로킹 방식이기 때문에 상위 프로세스는 하위 프로세스에게 일을 맡기고 자신의 작업을 계속 수행할 수도 있다.

예제코드

이 예제를 보면 boss 함수는 employee 함수에게 인형 눈알 100개를 붙히라고 지시한 후 바로 퇴근하였다.

상위 프로세스인 boss 함수는 employee 함수의 작업이 언제 끝나는지 관심이 없으며,

작업의 완료 신호는 콜백으로 넘겨진 눈알 결산 보고 작업이 대신 받아서 처리하고 있다.

🗣️ 비동기 & 논블로킹 방식은 여러 개의 작업을 동시에 처리할 수 있는 부분에서 효율적으로 할 수 있지만, 너무 복잡하게 얽힌 비동기 처리 때문에 개발자가 어플리케이션의 흐름을 일기 어려워지는 등의 문제가 있을 수 있다.

Javascript에서 Promise나 async/await와 같은 문법을 사용하는 이유도 이런 비동기 처리의 흐름을 좀 더 명확하게 인지하고자 하는 노력이다.

profile
개발공부일기

0개의 댓글