들어가며
블로킹과 논블로킹 그리고 동기와 비동기는 프로그래밍을 하다 보면 자주 만나게 되는 단어지만 이해하기 쉽지 않고 이해했다고 하더라도 막상 설명하자면 명확하게 설명하기 어려운 개념들입니다. 둘을 혼용하여 사용하는 경우도 있고 아예 같은 개념으로 보는 경우도 있습니다. 엄밀히 보면 둘은 관점이 다르며 크게 연관관계가 없습니다.
그만큼 직관적으로 이해하기 어려운 개념입니다. 오늘은 이 중요한 개념들에 대해서 자세히 알아보고 최대한 쉽게 정리해보려고 합니다. 각각의 대해서 정리해 보고 또 조합되었을 때의 작동 방식도 함께 다뤄보겠습니다.
📚 사전 지식
📗 함수
함수는 특별한 목적의 작업을 수행하기 위해서 독립적으로 만들어진 코드이다.
예를 들어 더하기 함수는 만들어진 목적에 맞게 넘겨받은 값들을 더해서 다시 돌려준다.
함수를 사용하는 가장 큰 이유는 반복적인 코드 작성을 피할 수 있기 때문이다.
📕 제어권
제어권은 코드를 실행할 권리이다.
내가 누군가에게 요청하면서 제어권을 넘겨준다면 다시 제어권을 돌려받을 때까지 아무 일도 하지 못한다.
📘 결괏값을 기다린다
결괏값은 내가 요청한 내용에 대한 결과다.
결괏값을 기다린다는 것은 내가 요청한 결과가 완료되었는지를 신경 쓰는지의 여부이다.
블로킹과 논블로킹
블로킹과 논블로킹의 관점은 제어권입니다. 즉, 제어권을 누가 가지고 있고 어떻게 처리하느냐에 따라서 나뉘게 됩니다.
블로킹, Blocking
블로킹은 응답자가 요청받은 작업을 완료할 때까지 제어권을 가지고 있는 방식입니다. 이때 요청자는 제어권을 넘겨주었기 때문에 다시 제어권이 돌아올 때까지 다른 작업을 진행할 수 없습니다.
1. 요청자가 응답자에게 요청할 때 제어권을 같이 넘겨줍니다.
2. 제어권을 가진 응답자는 제어권을 가지고 요청받은 일을 처리합니다. 이때 요청자는 제어권이 없으므로 멈춘 상태로 결과를 기다립니다.
3. 응답자는 처리가 끝나면 요청자에게 결과와 제어권을 돌려줍니다. 이때부터 요청자는 다시 자기 일을 할 수 있게 됩니다.
논블로킹, Non-Blocking
논블로킹은 응답자가 요청자에게 요청을 받고 제어권을 바로 돌려주는 것입니다. 제어권을 바로 돌려받기 때문에 요청자는 결과를 돌려받지 않아도 다른 작업을 진행할 수 있습니다.
1. 블로킹과 같은 방식으로 요청자는 응답자에게 요청할 때 제어권을 같이 넘겨줍니다.
2. 하지만 응답자는 요청자에게 제어권을 바로 돌려줍니다. 그렇기 때문에 요청자는 다른 작업을 할 수 있게 됩니다.
3. 응답자는 이제 요청받은 일을 처리하기 시작합니다.
4. 언젠가 응답자는 처리가 끝나면 요청자는 결괏값을 사용할 수 있게 됩니다.
✓ 블로킹(Blocking) I/O
- I/O 작업이 진행되는 동안 유저 프로세스는 자신의 작업을 중단한 채 대기하는 방식이다.
✓ 논 블로킹(Non-Blocking) I/O
- I/O 작업이 진행되는 동안 유저 프로세스의 작업을 중단시키지 않는 방식이다.
동기와 비동기
동기와 비동기의 관점은 순서와 결과입니다. 즉, 함수의 요청과 응답이 순서대로 이루어지는지 그리고 작업이 완료되었을 때 결과를 누가 신경 쓰는지에 따라서 나뉘게 됩니다.
동기, Synchronous
동기는 요청자가 응답자에게 요청한 일의 결과를 기다립니다. 요청자는 사실 다른 작업을 할 수 있는 입장이지만 계속 완료가 되었는지 확인하기도 하는 작업 이외에 다른 일을 하지 않습니다. 즉, 결과를 요청자가 신경 쓰는 경우입니다.
비동기, Asynchronous
비동기는 요청자가 요청할 때 콜백 함수를 같이 전달해서 응답자가 처리 완료할 때까지 신경 쓰지 않고 할 일을 하는 방식입니다. 그렇기 때문에 코드상으로 볼 때 순서가 뒤죽박죽 실행되는 것처럼 보이게 됩니다. 응답자는 요청받은 일이 완료되면 콜백 함수를 실행해서 요청자에게 완료되었음을 알립니다. 즉, 결과를 응답자가 신경 쓰는 경우입니다.
✓ 동기 방식
- I/O작업이 진행되는 동안 유저 프로세스는 결과를 기다렸다가 이벤트를 직접 처리하는 방식이다.
✓ 비동기 방식
- I/O 작업이 진행되는 동안 유저 프로세스는 자신의 일을 처리하다가 이벤트 핸들러에 의해 알림이 오면 처리하는 방식이다.
1. 동기와 블로킹 방식 ( Sync + Blocking )
"동기-블로킹 선생님"은 FM 감독관으로 학생들이 시험 문제를 푸는 동안 다른 일을 전혀 하지 않고 기다리십니다. 이후 학생들이 시험 문제를 모두 풀고 제출하고 나서야 비로소 시험지를 걷으시고 퇴실하십니다.
const call = () => teacher();
const teacher = () => {
console.log('선생님: 시험지를 나눠주신다.');
let 문제수 = 5;
student(문제수);
console.log('선생님: 시험지를 걷어가신다.');
}
const student = (문제수) => {
for(i=1; i<=문제수; i++){
console.log(`학생: ${i}번 문제 푸는중 ...`);
};
return console.log('모든 문제 풀이 완료');
}
선생님: 시험지를 나눠주신다.
학생: 1번 문제 푸는 중...
학생: 2번 문제 푸는 중...
학생: 3번 문제 푸는 중...
학생: 4번 문제 푸는 중...
학생: 5번 문제 푸는 중...
모든 문제 풀이 완료
선생님: 시험지를 걷어가신다.
블로킹과 동기가 결합된 방식은 가장 많이 쓰이는 조합으로 모든 실행이 순차적으로 일어나기 때문에 제어하기 쉽습니다.
2. 동기와 논블로킹 방식 ( Sync + Non-Blocking )
"동기-논블로킹" 선생님은 자유로운 감독관으로 학생들이 시험 문제를 푸는 동안 유튜브를 시청합니다. 이후 학생들이 시험 문제를 모두 풀고 제출하고 나면 기다렸다는 듯이 시험지를 걷으시고 퇴실하십니다.
선생님은 학생들이 문제를 푸는 동안 자유롭게 행동하지만 한 번씩 문제를 잘 풀고 있나 신경은 쓰고 있습니다.
const call = () => teacher();
const teacher = () => {
console.log('선생님: 시험지를 나눠주신다.');
let done;
let 문제수 = 5;
const generator = student(문제수);
while(!done) {
done = generator.next().done;
if (!done) {
console.log('선생님: 유튜브 시청 중 💻');
}
};
console.log('선생님: 시험지를 걷어가신다.');
}
function* student(문제수) {
for(i=1; i<=문제수; i++){
console.log(`학생: ${i}번 문제 푸는중 ...`);
yield;
};
return console.log('모든 문제 풀이 완료');
}
선생님: 시험지를 나눠주신다.
학생: 1번 문제 푸는 중...
선생님: 유튜브 시청 중 💻
학생: 2번 문제 푸는 중...
선생님: 유튜브 시청 중 💻
학생: 3번 문제 푸는 중...
선생님: 유튜브 시청 중 💻
학생: 4번 문제 푸는 중...
선생님: 유튜브 시청 중 💻
학생: 5번 문제 푸는 중...
선생님: 유튜브 시청 중 💻
모든 문제 풀이 완료
선생님: 시험지를 걷어가신다.
동기이므로 작업 완료 여부를 계속 신경 쓰지만 논블로킹이기에 완료 여부와 상관없이 다른 일을 처리할 수 있습니다.
3. 비동기와 논블로킹 방식 ( Async + Non-Blocking )
"비동기-논블로킹" 선생님은 정말 바쁜 감독관입니다. 들어오셔서 시험지만 나눠주고 반장에게 걷어서 가져다 달라고 부탁하고 다른 일을 처리하러 떠나십니다.
const call = () => teacher();
const teacher = () => {
let 문제수 = 5;
console.log('선생님: 시험지를 나눠주신다.');
setTimeout(() => student(문제수), 0);
console.log('선생님: 다른 업무보러 떠나신다.');
}
const student = (문제수) => {
for(i=1; i<=문제수; i++){
console.log(`학생: ${i}번 문제 푸는중 ...`);
};
return console.log('반장: 선생님께 시험지를 전달 해드린다.');
}
선생님: 시험지를 나눠주신다.
선생님: 다른 업무 보러 떠나신다.
학생: 1번 문제 푸는 중...
학생: 2번 문제 푸는 중...
학생: 3번 문제 푸는 중...
학생: 4번 문제 푸는 중...
학생: 5번 문제 푸는 중...
반장: 선생님께 시험지를 전달해 드린다.
비동기와 논블로킹 방식은 성능과 자원의 효율면에서 가장 우수합니다.
4. 비동기와 블로킹 ( Async + Non-Blocking )
"비동기-블로킹" 선생님은 이상한 감독관입니다. 바쁘신 탓에 들어오셔서 시험지만 나눠주고 반장에게 걷어서 가져다 달라고 부탁하고 다른 일을 처리하러 떠나셨지만 밖에서 시험지를 전달받으실 때까지 다른 일을 못하고 기다리기만 하십니다.
또 다른 예시로 세탁기에 빨래를 넣고 돌렸으니 이제 다른 일을 할 수 있는 상황임에도 불구하고 세탁기 앞에서 빨래가 완료될 때까지 아무 일도 못하고 서서 기다리는 상황입니다.
이처럼 "비동기-블로킹" 조합은 비동기이기 때문에 결과를 바로 처리하지 않아도 됩니다. 하지만 블로킹 방식이기 때문에 자신의 작업에 대한 제어권이 없습니다. 이런 모순적인 이유와 별 다른 장점이 없어서 일부러 사용하지는 않지만 개발자가 "논블로킹-비동기" 조합으로 구현하다가 실수 등으로 이 방식으로 동작하는 경우가 있습니다.
정리
💡 블로킹과 논블로킹: 제어권을 누가 가지고 있는가
💡 동기와 비동기: 순서대로 일어나는지와 결과를 누가 신경 쓰는가
Reference
'PROGRAMMING > CS' 카테고리의 다른 글
[CS] HTTP Status / Response Code ( Http 상태 / 응답 코드 정리 ) (45) | 2023.04.07 |
---|---|
[CS] 함수(Function)와 메서드(Method) 간단하고 정확하게 알아가기 (feat. Javascript) (26) | 2023.03.25 |
[CS] 함수형 프로그래밍의 특징(feat.Javascript) (36) | 2023.03.13 |
[CS] Argument와 Parameter의 차이 쉽게 이해하기 (feat. 인수 / 인자 / 매개변수 용어 정리) (36) | 2023.03.09 |
URL과 URI의 차이 그리고 URN까지 쉽게 이해하기 (50) | 2023.02.23 |