동기/비동기 그리고 블로킹/논블로킹
개요
음식점에서 일을 한다고 해보자.
가게에는 사장인 나 혼자서 하나의 음식 주문을 받으면 주문 접수부터 요리 그리고 서빙까지 해야한다.
그러나 한 번에 하나의 음식만 요리하면 손님은 밀리고 주문도 밀리고 불만이 접수될 것이다.
그래서 일반적으로는 냄비를 올리고 불을 켜고 다른 손님이 왔다면 주문을 받고 조리대로 간다. 그러면 손님의 주문을 받는 동안 물은 끓어있을 것이다.
동기와 비동기
동기란 순차적으로 진행되는 것을 말하며 일반적인 프로그래밍 방식이다.
위에서 아래로 하나의 로직이 완료되면 다음 라인이 실행된다.
console.log(1)
console.log(2)
console.log(3)
/* 실행 결과
1
2
3
/*
비동기란 순차적으로 진행되지 않는 것이다.
console.log(1)
setTimeout(() => console.log(2), 1000)
console.log(2)
/* 실행 결과
1
3
2
*/
블로킹과 논블로킹
블로킹은 프로세스나 스레드가 자원의 사용을 대기하는 방식과 관련된 개념이다.
예를 들어 블로킹은 호출된 작업이 완료될 때까지 호출한 프로세스나 스레드가 멈추고 기다리며 논블로킹은 호출된 작업이 즉시 반환되며 작업이 완료되지 않아도 호출한 프로세스나 스레드는 계속 실행된다.
이렇게 보니 위에서 살펴본 동기/비동기와 같은 설명인 것 같이 보인다.
블로킹과 논블로킹은 컴퓨터 시스템의 입출력 처리 방식과 관련된 개념으로 동기/비동기보다 먼저 등장했다.
컴퓨터 시스템에서 프로세스가 입출력을 수행할 때 자원을 기다리며 멈추는 방식(블로킹) 또는 자원을 기다리지 않고 다음 작업을 처리하는 방식(논블로킹)이 사용되었다.
이 개념은 하드웨어와 소프트웨어 간 인터페이스 문제를 해결하는 과정에서 등장하였으며
초기 입출력 시스템은 블로킹을 기본으로 하여 데이터가 디스크나 네트워크에서 올 때까지 CPU는 대기 상태에 멈춰있었고 이후 효율성을 높이고자 논블로킹 방식이 도입되었다.
프로세스가 대기상태가 아닌 동안 다른 작업을 수행할 수 있도록 설계되었다.
예를 들면 CPU가 파일을 읽을 때 파일이 디스크에서 읽혀질 때까지 멈추는 방식이 블로킹이고 CPU는 요청을 보낸 뒤 다른 작업을 계속 수행하고 파일 읽기가 끝나면 결과를 확인하는 식이다.
동기와 비동기는 보다 나중에 등장한 프로그래밍 패러다임으로
초기에는 작업이 순차적으로 이루어지는 동기 방식이 일반적이었다. 그러나 네트워크 프로그래밍과 같이 작업 지연이 길어지는 상황에서 비동기 방식이 필요하게 되었고 블로킹과 논블로킹을 기반으로 응용 프로그램 레벨에서 작업 완료를 확인하거나 콜백/이벤트를 처리하는 패턴으로 발전하였다.
정리하자면 블로킹/논블로킹은 하드웨어와 소프트웨어 간의 관계를 말한다. 작업 처리시 자원의 준비 상태에 따라 호출된 프로세스가 대기상태가 되느냐 아니면 즉시 반환되느냐를 정의한다.
동기/비동기는 프로그래밍 패러다임으로 작업이 완료된 후에 호출한 코드가 다음 작업을 진행할지 아니면 작업 완료와 상관없이 다음 작업을 진행할지를 결정한다.
블로킹/논블로킹 -> 자원의 사용 가능 여부
동기/비동기 -> 프로그램의 작업 흐름
위에서 살펴본 상황은 이 모두를 포함하고 있다.
블로킹/논블로킹 관점
블로킹: 사람(자원)이 물이 끓을 때까지 대기. 다른 작업을 수행하지 못함.
논블로킹: 사람(자원)이 물이 끓는 동안 다른 주문을 받거나 요리를 진행.
동기/비동기 관점
동기: 물이 끓는 작업이 끝나야 다음 작업을 시작.
비동기: 끓는 작업과 상관없이 다른 작업을 병렬로 수행하며, 물이 끓으면 알림을 받고 다음 단계를 이어감.
종업원이(자원) 한 명인 경우 앞의 손님의 주문이 길어져서 다음 손님의 주문을 먼저 받는 경우는 논블로킹이다. 하나의 자원이 하나의 테스크를 완료하지 않았더라도 다른 테스크를 수행할 수 있기 때문이다.