구분 방법
- 프로세스의 유휴 상태 → Blocking vs Non-blocking
- 프로세스의 수행 순서 보장 → Sync vs Async
키워드
제어권
- 본인(함수)의 코드를 실행할 권리
- 제어권을 가진 권을가진함수는 자신의 코드를 끝까지 실행한 후 자신을 호출한 함수에게 돌려준다.
- Blocking, Non-blocking 구분 방식
결과값을 기다리느냐
- A 함수에서 B 함수를 호출할 때 A 함수가 B 함수의 결과값을 기다리느냐의 여부
- Sync, Async 구분 방식
Blocking vs Non-blocking
- 처리되어야 하는 작업이 전체 작업 흐름을 막느냐
- 제어권이 누구한테 있느냐
Blocking
자신의 작업을 진행하다가 다른 주체의 작업이 시작되면 다른 작업이 끝날 때까지 기다렸다가 자신의 작업을 다시 시작하는 것
- A 함수가 B 함수를 호출하면서 B에게 제어권을 넘긴다.
- B가 함수를 실행하는 동안 A는 B에게 제어권을 넘겨주었기 때문에 함수 실행을 잠시 멈춘다.
- B함수는 실이 끝나면 자신을 호출한 A에게 제어권을 돌려준다.
Non-blocking
다른 주체의 작업에 관련없이 자신의 작업을 하는 것
- A 함수가 B 함수를 호출하면서 실행만 시키고 제어권은 A가 그대로 가지고 있는다.
- A 함수는 제어권을 계속 가지고 있기 때문에 자신의 코드를 계속 실행한다.
Synchronous vs Asynchronous
- 처리해야 할 작업들을 어떠한 흐름인가
- 호출되는 함수의 작업 완료 여부를 신경쓰냐
- 함수 실행/리턴 순차적인 흐름을 따르느냐
Synchronous 동기
작업을 동시에 수행하거나, 동시에 끝나거나, 끝나는 동시에 시작한다.
동기 방식은 작업의 순차적인 흐름만 지켜진다면 블로킹이든 논블로킹이든 상관 없다.
- 함수 A가 함수 B를 호출한 뒤
- A가 B의 작업 완료 후 리턴을 기다리거나
- 바로 리턴 받더라도 미완료 상태이면 작업 완료 여부를 스스로 계속 확인하고 신경쓰는 것
Asynchronous 비동기
시작, 종료가 일치하지 않고, 끝나는 동시에 시작하지 않아도 된다.
- 함수 A가 함수 B를 호출할 때 콜백 함수를 함께 전달한다.
- A는 B를 호출한 후 B의 작업 완료 여부를 신경쓰지 않는다.
조합
Sync + Blocking
- 동기: 함수 A는 함수 B의 리턴값이 필요하다.
- 블로킹: 제어권을 함수 B에게 넘겨주고, B가 실행 완료 후 리턴값과 제어권을 돌려줄 때까지 A는 계속 확인하고 기다린다.
예제
Sync + Non-blocking
- 논블로킹: 함수 A는 함수 B에게 제어권을 주지 않고 자신의 코드를 계속 실행한다.
- 동기: A는 B의 리턴값이 필요하기 때문에 중간에 B에게 함수 실행을 완료했는지 확인한다.
예제
Async + Blocking
잘 쓰이지 않는다.
- 비동기: 함수 A는 함수 B의 리턴값을 신경쓰지 않고 콜백함수를 보낸다.
- 블로킹: B 함수 작업에 관심없음에도 불구하고 A는 B에게 제어권을 넘긴다.
A는 자신과 관련없는 B 의 작업이 끝날 때까지 기다려야 한다.
예제
- Sync + Blocking과 성능 차이가 비슷하기 때문에 사용하는 경우가 거의 없다.
- 실수로 발생하는 경우
- Node.js + MySQL 조합
- Node.js에서 비동기적으로 DB 작업 수행해도 블로킹 방식으로 작동하는 MySQL 드라이버를 거치게 된다.
Async + Non-bloking
- 논블로킹: A는 제어권을 B에게 주지 않고 자신의 코드를 계속 실행한다.
- 비동기: 함수 B를 호출할 때 콜백함수를 함께 준다. B는 자신의 작업이 끝나면 받은 콜백 함수를 실행한다.
특징
- 여러 개의 작업을 동시에 처리할 수 있으므로 효율적이다.
- 너무 복잡하게 얽힌 비동기 처리 때문에 개발자가 어플리케이션의 흐름을 읽기 어려워질 수도 있다.
- JavaScript에서
Promise
나 async
, await
와 같은 문법을 사용하는 것도 비동기 처리의 흐름을 더 명확하게 인지하고자 하는 노력이다.
예제
코드
function employee (maxDollCount = 1, callback) {
let dollCount = 0;
const interval = setInterval(() => {
if (dollCount > maxDollCount) {
callback();
clearInterval(interval);
}
dollCount++;
console.log(`직원: 인형 눈알 붙히기 ${dollCount}번 수행`);
}, 10);
}
function boss () {
console.log('사장: 출근');
employee(100, () => console.log('직원: 눈알 결산 보고'));
console.log('사장: 퇴근');
}
boss();
사장: 출근
사장: 퇴근
직원: 인형 눈알 붙히기 1번 수행
직원: 인형 눈알 붙히기 2번 수행
...
직원: 인형 눈알 붙히기 100번 수행
직원: 눈알 결산 보고
- boss는 employee의 작업이 언제 끝나는지 관심 없다.
- 작업 완료 신호는 callback 함수로 넘겨진 눈알 결산 보고 작업이 대신 받아서 처리하고 있다.
출처