diff --git "a/7\354\243\274\354\260\250/4. Blocking vs Non-blocking & Synchronous vs Asynchronous.md" "b/7\354\243\274\354\260\250/4. Blocking vs Non-blocking & Synchronous vs Asynchronous.md" new file mode 100644 index 0000000..f431c6a --- /dev/null +++ "b/7\354\243\274\354\260\250/4. Blocking vs Non-blocking & Synchronous vs Asynchronous.md" @@ -0,0 +1,241 @@ +# 4. Blocking vs Non-blocking & Synchronous vs Asynchronous + +**Blocking**, **Non-blocking**, **Synchronous**, **Asynchronous**. + +비슷해 보이지만 **다른 개념**이며, I/O 처리, 네트워크 통신, 시스템 프로그래밍 등에서 자주 등장합니다. + +--- + +![image](https://github.com/user-attachments/assets/36a30d33-92ae-4fda-97b0-af73e625c3a6) + + +## 🍤 용어 정리 + +| 구분 | 의미 | 주체 | 비유 | +| --- | --- | --- | --- | +| **Blocking** | 요청한 작업이 끝날 때까지 **현재 스레드가 대기** | 호출자 (Thread) | "창구 앞에서 기다림" | +| **Non-blocking** | 요청하자마자 **바로 리턴**, 다른 일 가능 | 호출자 (Thread) | "번호표 받고 돌아다님" | +| **Synchronous** | **작업 결과를 직접 확인**해야 다음 진행 | 제어 흐름 (코드 레벨) | "일일이 확인하며 작업" | +| **Asynchronous** | 결과는 **콜백 등으로 나중에 통보**, 바로 다음 코드 실행 | 제어 흐름 (코드 레벨) | "작업 지시 후 다른 일 먼저" | + +
+ +--- + +
+ +## 🛑 1️⃣ Blocking이란? + +> 호출한 함수가 결과를 호출된 함수에게 받 때까지 제어권을 넘겨주고 기다림 +> +- 대표 예: `read()`, `accept()` 등 전통적 I/O API +- CPU가 스레드를 멈추고 **기다리기만 하므로 비효율** + +```java +InputStream in = socket.getInputStream(); +int data = in.read(); // 이 줄에서 블로킹! 데이터 올 때까지 대기 + +``` + +🐙 "Blocking은 스레드 점유 -> 병렬성 저하" + +### 🙋‍♂️ Blocking을 쓰는 경우? + +- 별다른 설정 없이 대부분의 I/O 함수는 기본적으로 Blocking 방식입니다. +- **Java의 Socket, FileInputStream, Scanner 등 대부분의 전통 API는 Blocking** 방식입니다. +- `read()`, `accept()`, `connect()` 등 +- **동시 요청 수가 적거나 처리 순서를 보장해야 할 때**, 오히려 Blocking이 직관적이고 안정적인 선택일 수 있습니다. + +📌 Blocking 코드를 효율적으로 쓰기 위해선: + +- **스레드 풀**을 이용하여 요청을 분산 처리하거나 +- 특정 작업에 대한 **타임아웃 설정**을 활용하는 것이 중요합니다. + +
+ +--- + +
+ + +## 🍟 2️⃣ Non-blocking이란? + +> 함수 호출 시 즉시 리턴, 데이터가 준비 안 되어도 제어권 유지 +> +- 예: Java NIO, select/poll 기반 +- 스레드는 **다른 작업을 계속 수행 가능** +- configureBlocking(false)를 설정하면, read()는 데이터가 안 와도 기다리지 않음 + + 즉시 리턴되는데, 데이터가 없으면 bytesRead == 0 또는 -1 + + +```java +SocketChannel channel = SocketChannel.open(); +channel.configureBlocking(false); // 논블로킹 설정 +int bytesRead = channel.read(buffer); // 준비 안 되어 있으면 -1 또는 0 반환 + +``` + +🍤 고성능 서버, 이벤트 기반 아키텍처에 적합 + +### 🙋‍♂️Non-blocking을 쓰려면? + +- 계속 read() 호출해서 데이터 있는지 확인하거나(제어 흐름이 결과를 직접 확인=**Synchronous**), +- Selector 같은 이벤트 감지기(나중에 이벤트 발생시 자동호출=**Asynchronous**)와 함께 써야 효율적입니다. + +```java +while (true) { + int bytesRead = channel.read(buffer); + + // 계속 확인 = polling + if (bytesRead > 0) { //준비된 상태 + System.out.println("데이터 읽음!"); + } else { + // 데이터 아직 없음 → 다른 일 하거나 다시 시도 + } +} + +``` + +
+ + +--- + +
+ + +![image](https://github.com/user-attachments/assets/db16d883-5a68-4be3-ba5e-b7a467c03f75) + + +## 🧶 3️⃣ Synchronous란? + +> 함수 호출 → 결과 반환 → 다음 코드 실행 (순차적 흐름) +> +- 익숙한 코드 흐름, 직관적 +- 단점: 느린 작업이 전체 흐름을 멈춤 + +```java +String result = syncApi.call(); // 결과 기다림 +System.out.println(result); // 결과 이후 실행( ← 결과 없으면 실행 안 됨) + +``` + +
+ + +--- + +
+ + +## 🌶 4️⃣ Asynchronous란? + +> 결과는 콜백/이벤트리스너 등으로 나중에 받고, 먼저 다음 작업 실행 +> +- 예: Java CompletableFuture, JS의 Promise, async/await +- 콜백 : 함수가 작업을 던져놓고 다음 코드로 넘어가지만, + + 작업이 끝났을 때 실행할 함수(=콜백)를 미리 등록해두어 나중에 결과를 받을 수 있는것 + + +```java +CompletableFuture.supplyAsync(() -> { + return slowTask(); +}).thenAccept(result -> { + System.out.println("콜백으로 결과 도착: " + result); +}); +System.out.println("바로 다음 코드 실행!"); + +``` + +실제 출력 결과 + +``` +바로 다음 코드 실행! +콜백으로 결과 도착: (slowTask의 결과) + +``` + +🧨 비동기 처리: 네트워크 요청, 디스크 I/O에 매우 효율적 + +
+ + +--- + +
+ + +## 👊구분 + +*Blocking/Non-blocking: 스레드가 멈추냐 안 멈추냐* + +*Synchronous/Asynchronous: 코드 실행이 결과를 기다리냐, 콜백으로 처리하냐* + +| 구분 | 초점 | 스레드 멈춤 여부 | 설명 | +| --- | --- | --- | --- | +| **Blocking / Non-blocking** | **스레드의 상태** | ✅ 관련 있음 | 함수 호출 시 스레드가 멈추느냐 바로 리턴되느냐 | +| **Synchronous / Asynchronous** | **제어 흐름의 구조** | ❌ 직접 관련 없음 | 코드를 순차적으로 실행하느냐, 콜백/이벤트로 처리하느냐 | + +
+ + +--- + +
+ + +## 🐡 조합별 정리 + +| 조합 | 특징 | +| --- | --- | +| **Synchronous + Blocking** | 호출한 함수가 결과를 받을 때까지 멈추고 대기. 전통적인 방식. | +| **Synchronous + Non-blocking** | 결과를 직접 확인하지만, 함수는 바로 제어권을 반환. 계속 polling 등 필요. | +| **Asynchronous + Blocking** | 결과는 나중에 받지만, 그 결과를 받기 전까지 스레드는 멈추고 기다림. 비동기로 던져도 의미가 없어 비효율적. 현실에선 거의 쓰이지 않음. | +| **Asynchronous + Non-blocking** | **가장 효율적!** 결과는 나중에 콜백/이벤트로 받고, 호출 직후 다른 작업 가능. | + +### 🎯 Synchronous + Non-blocking vs Synchronous + Blocking + +| 항목 | Synchronous + Blocking | Synchronous + Non-blocking | +| --- | --- | --- | +| ✅ 코드 흐름 | 순차적이며 직관적 | 순차적이지만 polling 필요 | +| ✅ 스레드 점유 | 요청마다 스레드가 멈춤 | 스레드는 계속 작동 가능 | +| ✅ 효율성 | 단순하지만 동시성 낮음 | 스레드 낭비는 적지만 관리 복잡 | +| ✅ 적합한 상황 | 로직이 단순하고 I/O 양 적은 환경(ex. CLI 유틸, 테스트 코드) | 빠르게 반복적으로 결과를 확인해야 하는 상황(ex. 파일 상태 반복 체크 등) | + +💬 결론: Non-blocking이 효율적일 수 있지만, 코드 복잡도가 올라가고 polling이 필요한 경우 **Synchronous + Blocking이 오히려 더 단순하고 안정적**일 수 있음. + +
+ + +--- + +
+ + +## 🧃 팁 + +- 🍤 서버 개발: 대규모 동시성 처리 → Non-blocking + Asynchronous 조합 권장 +- 🍜 로직 간 의존도 높음: Synchronous가 관리 쉬움 +- 🌶 빠른 응답 필요: Asynchronous 방식 추천 (이벤트 루프 기반) + +**추가자료 :** + +- https://velog.io/@akfls221/%EB%8F%99%EA%B8%B0%EB%B9%84%EB%8F%99%EA%B8%B0-NonBlocking-Blocking%EA%B3%BC-%EC%9B%B9-%EC%84%9C%EB%B2%84%EC%9D%98-%EA%B4%80%EA%B3%84 + +**Spring MVC**는 기본적으로 **블로킹 구조**지만, 대부분의 웹 서비스에서는 무리 없이 작동 +동시성 최적화나 대규모 트래픽 처리가 필요하다면 Spring WebFlux처럼 논블로킹 프레임워크가 적합 + +
+ + +--- + +
+ + +## 🐙 참고자료 + +- https://homoefficio.github.io/2017/02/19/Blocking-NonBlocking-Synchronous-Asynchronous/?utm_source=chatgpt.com +- https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Network/%5BNetwork%5D%20Blocking%2CNon-blocking%20%26%20Synchronous%2CAsynchronous.md#network-blockingnon-blocking--synchronousasynchronous