개발을 하다보면, 동기 코드여서 혹은 비동기 코드여서 문제가 생겼다는 이야기가 종종 나옵니다. 하지만 동기와 비동기의 개념이 명확히 이해되지 않으면, 문제의 원인을 정확히 파악하기 어렵습니다. 이번 글에서는 동기와 비동기의 개념을 명확히 이해하고, 각각의 차이점에 대해서 공유해보려고 합니다.
동기는 작업이 순서대로 실행되며, 하나가 끝나야 다음 작업이 시작되는 방식입니다.
즉, 기다렸다가 -> 작업이 끝나면 -> 다음 작업이 시작되는 흐름입니다.
// 동기 처리 흐름 그림
요청 1 ──────── 처리 ──────── 완료
↓
요청 2 ──────── 처리 ──────── 완료
↓
요청 3 ──────── 처리 ──────── 완료
자바스크립트로 예를 들면, 동기 코드는 다음과 같이 작성됩니다.
function task1() {
console.log("Task 1 시작");
console.log("Task 1 끝");
}
function task2() {
console.log("Task 2 시작");
console.log("Task 2 끝");
}
task1();
task2();
// 출력:
// Task 1 시작
// Task 1 끝
// Task 2 시작
// Task 2 끝
동기의 장점은, 코드가 직관적이고 실행 순서 예측이 쉬우며 (순서가 보장됨) 디버깅이 비교적 간단합니다. 반대로 단점은, 오래 걸리는 작업이 있으면 전체가 멈추게 되고, I/O 작업 (DB, API, 파일 읽기 등)에 비효율적입니다.
비동기는 작업을 요청해두고, 끝날 때까지 기다리지 않고 다음 작업을 실행하는 방식입니다.
즉, 일단 시켜놓고 -> 다른 작업 먼저 하고 -> 끝나면 나중에 처리하는 방식입니다.
// 비동기 처리 흐름 그림
요청 1 ────── 처리 중 ────── 완료
요청 2 ─── 처리 ─── 완료
요청 3 ── 처리 ─ 완료
// 타임라인
시간 →
Task1 시작 ──────────────┐
Task2 시작 ── 완료 │
Task3 시작 ─ 완료 │
└─ Task1 완료
자바스크립트로 예를 들면, 동기 코드는 다음과 같이 작성됩니다.
console.log("시작");
setTimeout(() => {
console.log("비동기 작업 완료");
}, 2000);
console.log("끝");
// 출력:
// 시작
// 끝
// 비동기 작업 완료
사용자가 버튼을 클릭했을 때 서버에 API 요청을 하고 (3초 소요) 결과를 반환하는 상황일 때.
동기라면 3초 동안 화면이 멈춰 UX 최악의 상황이 발생하지만,
비동기는 요청 보내고, 로딩 UI 보내주고, 응답 오면 화면 업데이트를 할 수 있어
현대 웹/앱 개발에서 비동기는 필수입니다. (동시에 여러 작업 진행 가능, 단 완료 순서는 보장되지 않음)
참고로, 비동기 !== 멀티스레드입니다. JavaScript 는 싱글 스레드지만 Event Loop + Web APIs + Callback Queue 덕분에 비동기처리가 가능합니다.
// Event Loop 구조 그림
Call Stack
↓
Web APIs (Timer, Fetch 등)
↓
Callback Queue
↓
Event Loop
↓
Call Stack으로 다시 이동
JS 는 싱글 스레드지만, 브라우저가 대신 작업해주고 끝나면 다시 알려주는 구조
먼저 실행 방식 관점에서 동기는 순차 실행, 비동기는 병렬적으로 실행됩니다.
대기 방식 관점에서 동기는 작업이 끝날 때까지 기다리고, 비동기는 기다리지 않고 다음 작업을 실행합니다.
코드 난이도 관점에서 동기는 쉬운 편이지만, 비동기는 상대적으로 복잡할 있습니다.
성능 관점에서 동기는 I/O에 비효율적이고, 비동기는 I/O에 효율적입니다.
대표적으로 동기는 일반 함수 호출, 비동기는 Promise, async/await, 콜백 함수 등으로 구현됩니다.
실무에서의 관점으로 봤을 때도,
비동기는 API 호출, DB 조회, 파일 읽기, 네트워크 통신, 대용량 데이터 처리 등에 용이하고
동기는 단순 계산, 짧은 로직 실행, 순차 실행이 중요한 경우 등에 적합합니다.
동기는 "기다린다", 비동기는 "일단 시켜놓고 다른 거 한다" 로 생각하면 이해하기 쉽습니다.
성능과 사용자 경험을 위해 I/O 작업은 반드시 비동기적으로 처리하는 습관이 중요합니다.