학습 목표
- 동기/비동기 방식의 차이를 이해한다.
- Callback 함수에 대해 설명한다.
컴퓨터 동작의 역사
단일 프로세스
- 컴퓨터는 CPU의 연산 속도가 정말 빠름에도 하나의 프로세서가 하나의 프로세스만을 처리할 수 있음
- 또한, 하드웨어적 접근의 경우도 하나의 프로세스였기에
Input/Output(I/O), 이하 입출력
의 경우도 입출력을 처리하면 연산을 못하고, 연산을 하면 입출력을 처리하지 못했음
프로세서의 연산 속도는 굉장히 빨랐고, 하드웨어는 느렸기때문에 둘의 속도 차이에 의한 비효율적 상황이 발생했음
CPU와 I/O의 분리
- 이러한 일은 그 당시 약 1950/60년대 전후로는 '매우 매우 매우 비싼' 컴퓨터가 고작 하드웨어 때문에 계산을 처리하지 못하는 일은 있을 수 없는 일이었음
- 이를 개선하기 위해 CPU와 I/O를 분리하는 I/O Channel 방식이 등장함
- 그리고 이를 위해 각 프로세스의 상황을 알 수 있는 Interupt 방식이 탑재되게 되었음
- 이는 CPU는 I/O 관련 명령만 I/O 전달을, I/O 처리가 끝나면 I/O 컨트롤러는 인터럽트를 CPU에 전달하여 CPU가 입출력 작업의 시작과 끝을 관여하게 되었음
CPU와 I/O 처리
- 이러한 입출력 관리에서 CPU는 입출력 작업의 시작과 끝만 관리할 수 있지, 작업 자체와 결과를 관리할 수 없었고 이에 따라 운영체제가 입출력을 처리하는 블로킹과 논블로킹 I/O와 I/O 작업에 따라 프로그램을 관리하는 동기와 비동기 방식이 탄생함
Blocking I/O
- User-level에서 다룰 수 없는 I/O를 다루기 위한 것으로 우리가 사용할 때 직접 I/O를 다루는 것 같지만 실제로는 OS에게 요청을 보내고, OS가 작업을 처리해주는 것
- 이 때 I/O 작업 결과를 보장받기 위해 운영체제는 Blocking 됨
동기, Synchronus
- 이 때 프로그램의 처리 흐름이 상관없이 계속 일어난다면?
- I/O 작업이 진행 중임에도 프로그램은 종료되버릴 수 있음
- 이를 방지하기 위해 프로그램의 흐름은 작업이 완료될 때까지 중단됨
Non-Blocking I/O
- 문제는 Blocking I/O 작업 방식은 OS와 하드웨어 수준의 작업이 이루어지고, 사용자는 CPU 자원을 거의 사용하지 않는다는 것
- 작업이 완료되기 전까지 사용자는 아무 작업도 할 수 없음
- 이를 개선하기 위해 사용자 레벨에서는 OS에게 I/O작업을 요청하지만 OS는 작업 결과를 바로 반환하는 Non-Blocking I/O 방식이 탄생함
- 하지만 사용자가 지속적으로 결과를 확인하지 않으면, 작업 결과를 알 수 없는 문제점이 발생함
비동기, Asynchronus
- 그렇다면 사용자 프로그램은 진행되고, I/O 작업 완료 시 운영체제가 한번만 알려주면 좋지 않을까?
- 이렇게 나온 것이 Asynchronous Event-Driven으로 I/O 작업을 요청한 곳에 Callback Function을 통해 이벤트를 발생시켜 작업의 완료를 알려줌
(Sync/Async == Blocking/Non-Blocking) = ?
- Sync/Async와 Blocking/Non-Blocking은 비슷한 것 같지만 다른 개념
- Blocking/Non-Blocking은 작업의 처리 결과를 어떻게 할 것인가?
- 완료되는 시점까지 멈출 것인가? 바로 반환할 것인가?
- Synchronous/Asynchronous는 호출한 작업을 어떻게 처리할 것인가?
- 결과가 반환되길 기다릴 것인가? 기다리지 않을 것인가?
- 이에 따라 Sync는 Blocking이 될 수 있음
비동기의 구현
- 그렇다면 Callback Function을 통한 비동기의 구현은 실제로 어떻게 이루어질까?
- 가장 대표적인 구현법은 자바스크립트의 콜백 함수가 있음
콜백 이전의 중요한 1급 객체
- 왜 자바스크립트가 콜백 함수의 대표적 구현법일까?
- 자바스크립트는 함수를
1급 객체(First Class Object)
로 취급하기 때문임
- 1급 객체의 가장 큰 특징은 함수의 인자로 함수를 전달할 수 있다는 것임
Callback Function
function async(callback) {
setTimeout(() => {
callback("1초 후 실행");
}, 1000);
}
async(function (msg) {
console.log(msg);
});
- 가장 대표적인 콜백 구현법
- 실행할 함수(Caller)에 콜백 함수를 인자로 전달
- 콜백 함수는 setTimeout으로 인한 비동기 작업이 완료 후 1초 후 실행되고, 이 때 콜백 함수는 해당 작업을 실행할 수 있음
번외, Promise/Then과 Async/Await
- 콜백 함수는 그 안에서만 로직을 정의하고 처리함으로써 콜백과 콜러의 구분이 어렵고, 상태를 관리할 수 없어 코드가 복잡해졌음
- 이를 개선하기 위해 Promise/Tnen과 Async/Await이 등장함