동기, 비동기 그리고 Blocking, Non-Blocking 2편 | 조합해볼까?
동기, 비동기 그리고 Blocking, Non-Blocking 1편 | 비교해볼까?목차들어가기동기, 비동기, Blocking, Non-Blocking동기비동기BlockingNon-Blocking결국참고 들어가기개발 공부하다 보면 동기, 비동기라는 단어가
pirateturtle.tistory.com
목차
- 코드로 작성해보자
- 동기, 비동기, Blocking, Non-Blocking 조합
- 동기 + Blocking
- 동기 + Non-Blocking
- 비동기 + Non-Blocking
- 비동기 + Blocking
- 끝맺으며
- 참고
코드로 작성해보자
2편에서 조합한 이론적 내용을 바탕으로 실제 코드를 작성해봅시다. Javascript 언어를 이용하여 작성합니다. Javascript는 단일 스레드 이므로 동기적인 특징을 가지고 있습니다. 하지만 브라우저나 Node.js에서는 Javascript 엔진만 있지 않습니다. Event Loop를 통해 Promise 객체, Web api, libuv를 이용하여 비동기 동작을 구현할 수 있습니다. 따라서 Promise, Async Await에 대한 내용을 충분히 이해한 뒤 읽어보시길 권장드립니다.
동기, 비동기, Blocking, Non-Blocking 조합
각 조합의 예시 코드는 A 함수가 1초의 실행시간이 걸리는 B 함수를 호출하는 흐름입니다. 그 과정에서 B 함수가 Blocking인지 Non-Blocking인지 차이점을 가지고 있습니다.
동기 + Blocking
function functionB() {
console.log("Function B started");
const startTime = Date.now();
while (Date.now() - startTime < 1000) {
// 1초 기다리는 작업중...
}
console.log("Function B completed");
}
function functionA() {
console.log("Function A started");
functionB();
console.log("Function A completed");
}
functionA();
// 출력
// Function A started
// Function B started
// Function B completed
// Function A completed
서두에서 설명했다시피 Javascript는 기본적으로 동기적인 특징을 가지고 있습니다. 그래서 별다른 키워드를 사용하지 않아도 동기를 표현할 수 있습니다. B의 1초 기다리는 작업이 끝날때까지 B의 작업은 끝나지 않습니다. B의 작업이 끝나지 않으므로 A도 대기상태입니다. B가 완료되면서 A는 제어권을 갖게되고 마무리하게 됩니다.
동기 + Non-Blocking
Non-Blocking을 표현하려면 어떻게 해야할까요? 우선 A함수가 B함수를 호출하고 B함수도 진행하면서 A함수도 진행해야한다. 여기서 A함수는 B함수가 끝났는지 계속 확인하는 작업이다. 그런데 Javascript는 단일스레드라서 A함수와 B함수를 동시에 진행할 수 없다. 그래서 다른 도움을 받는 방법을 떠올려보았다.
1. Promise, setTimeout
Promise 객체, Web Api를 이용하면 동시에 진행하는 것처럼 표현할 수 있다. 하지만 이 방법을 바탕으로 실행하면 A함수가 종료되기 전에 B함수의 종료를 확인할 수 없습니다. 왜냐하면 Call Stack에서 A함수가 종료되어야 Queue에 들어간 Promise.resolve, setTimeout의 콜백함수가 실행 가능하기 때문입니다.
2. worker thread
메인 스레드말고 다른 스레드를 사용하면 A함수와 B함수가 동시에 실행할 수 있습니다. 하지만 A함수와 B함수는 이벤트를 이용해서 통신합니다. 즉, A함수가 B함수의 완료를 확인하는 방법은 B함수로부터 이벤트를 받아야하는 것입니다. 그럼 표현하고자 했던 A함수가 B함수의 완료를 확인하는 것이 아닙니다. 그 반대가 표현된 겁니다.
그래서 이번 조합은 Javascript로 표현하지 못했습니다. 만약 아이디어가 떠오르시면 댓글 작성부탁드리겠습니다.
비동기 + Non-Blocking
function functionB() {
console.log("Function B started");
return new Promise((resolve) => {
setTimeout(() => {
console.log("Function B completed");
resolve();
}, 1000);
});
}
async function functionA() {
console.log("Function A started");
const promiseB = functionB();
for (let i = 1; i <= 5; i++) {
console.log(`다른 작업 중 ${i * 20}%`);
await new Promise((resolve) => setTimeout(resolve, 500));
}
await promiseB;
console.log("Function A completed");
}
functionA();
// 출력
// Function A started
// Function B started
// 다른 작업 중 20%
// 다른 작업 중 40%
// Function B completed
// 다른 작업 중 60%
// 다른 작업 중 80%
// 다른 작업 중 100%
// Function A completed
A함수, B함수 간의 통신은 비동기로 이루어집니다. 그러므로 B함수의 완료는 A함수가 확인할 필요가 없어지고 B함수가 완료될때까지 A함수가 대기할 필요도 없어집니다. 이러한 상황을 Promise 객체와 Async Await 키워드를 이용하여 표현할 수 있습니다. A함수는 B함수를 호출하고 Promise 객체를 받습니다. 그리고 다른 작업을 수행합니다. B함수는 완료되면 A함수에게 알려줍니다. 하지만 A함수는 B함수가 완료되어야만 할 수 있는 작업의 시점을 마음대로 정할 수 있습니다. 그런데 코드를 보다보면 이상한 점이 있습니다. for문 안에 있는 다른 작업을 하면서 Promise 객체를 다루는 것을 볼 수 있습니다. 정확히 동작을 표현하면 Promise 객체를 이용하여 PromiseB의 완료시점을 알아내고 있습니다. 그럼 B함수가 A함수에게 완료됨을 알려주는 게 아니라서 잘못 표현된게 아닐까요? 정확히 이야기하자면 맞습니다. 어쩌면 바로 위에 있는 동기 + Non-Blocking 조합의 표현을 어느정도 섞였습니다. 그럼 왜 이런 코드로 표현했을까요? 사실 이 글을 작성하면서 깨달았다는 점이 이글의 치부입니다. 차라리 이 코드를 동기 + Non-Blocking 조합의 코드로 작성하고 worker thread로 비동기 + Non-Blocking 조합의 코드로 작성하는 건 어떠신가요? 더 좋은 아이디어가 있다면 댓글로 작성부탁드립니다. (다시 테스트한 후, 이 글은 수정될 예정이에요)
비동기 + Blocking
function functionB() {
console.log("Function B started");
return new Promise((resolve) => {
setTimeout(() => {
console.log("Function B completed");
resolve();
}, 1000);
});
}
async function functionA() {
console.log("Function A started");
await functionB();
console.log("Function A completed");
}
functionA();
// 출력
// Function A started
// Function B started
// Function B completed
// Function A completed
마지막으로 Javascript를 이용하신다면 많이 작성하는 코드입니다. Promise로 비동기를 만든 다음 Blocking이 필요한 부분에서는 await로 대기하기 때문입니다. 이 글에서는 Promise, Async Await에 대한 설명은 논외로 벗어났다고 생각되어 참고 링크에 작성한 MDN 문서로 갈음하겠습니다.
끝맺으며
이렇게 동기, 비동기, Blocking, Non-Blocking에 대해서 알아보았습니다. 개념의 설명 글을 읽을 때는 완전 헷갈려서 '같은 뜻의 다른 표현인가?' 했습니다. 이젠 다름을 깨닫고 조금씩 차이점을 이해할 수 있었습니다. 하지만 아직 코드로 완전히 표현하기는 어려운 것 같습니다. 언어적 특성때문에 어려울 수도 있겠지만, 계속 학습하다보면 또 새로운 깨달음을 얻을 수 있을거라 믿습니다.
참고
'Developer > Study' 카테고리의 다른 글
프런트엔드 개발을 위한 보안 입문 1~3장 | 보안과 HTTP (3) | 2025.03.22 |
---|---|
동기, 비동기 그리고 Blocking, Non-Blocking 2편 | 조합해볼까? (0) | 2025.03.02 |
동기, 비동기 그리고 Blocking, Non-Blocking 1편 | 비교해볼까? (0) | 2025.02.02 |
fireEvent와 userEvent 구현체 살펴보기 (0) | 2024.01.21 |
리액트의 렌더링이란? (0) | 2023.02.28 |
Javascript Module System (0) | 2023.01.23 |
[JavaScript] Hoisting 이란? (0) | 2022.01.27 |
댓글