2025-02-22T01:33:42

This commit is contained in:
2025-02-22 01:33:42 +09:00
parent b5f6bbb1e0
commit ee63c56f2b
9 changed files with 1451 additions and 0 deletions

223
docs/07_코루틴.md Normal file
View File

@@ -0,0 +1,223 @@
# **코틀린의 코루틴과 비동기 프로그래밍**
코틀린은 **코루틴(Coroutines)** 을 통해 **비동기(Asynchronous) 프로그래밍**을 쉽고 직관적으로 구현할 수 있다.
코루틴은 **스레드보다 가볍고 효율적**이며, **콜백 지옥을 피할 수 있는 강력한 기능**을 제공한다.
이 글에서는 **코루틴의 개념과 주요 기능**을 설명하고,
**비동기 프로그래밍을 구현하는 예제**를 함께 살펴보겠다. 🚀
---
## **1. 비동기 프로그래밍이란?**
비동기 프로그래밍은 **작업이 완료될 때까지 기다리지 않고 다음 코드를 실행하는 방식**이다.
즉, **시간이 오래 걸리는 작업(예: 네트워크 요청, 파일 I/O 등)** 도 프로그램이 멈추지 않고 실행된다.
### **1.1. 전통적인 방식 (콜백 지옥)**
자바에서는 비동기 작업을 콜백(callback) 방식으로 처리해야 한다.
콜백이 중첩되면 **콜백 지옥(Callback Hell)** 이 발생할 수 있다.
#### **자바의 콜백 예제**
```java
void fetchData(Callback callback) {
new Thread(() -> {
try {
Thread.sleep(2000); // 2초 대기 (네트워크 요청 가정)
callback.onSuccess("데이터를 가져왔습니다!");
} catch (InterruptedException e) {
callback.onError(e);
}
}).start();
}
interface Callback {
void onSuccess(String data);
void onError(Exception e);
}
public static void main(String[] args) {
fetchData(new Callback() {
@Override
public void onSuccess(String data) {
System.out.println(data);
}
@Override
public void onError(Exception e) {
System.out.println("에러 발생: " + e.getMessage());
}
});
}
```
> - `fetchData()` 가 비동기적으로 데이터를 가져오지만, **콜백을 계속 중첩해서 작성해야 한다.**
> - 코드가 복잡해지고 가독성이 나빠지는 문제가 있다.
---
## **2. 코루틴이란?**
**코루틴(Coroutines)** 은 **비동기 프로그래밍을 간결하고 가독성 높게** 구현할 수 있도록 도와준다.
코루틴을 사용하면 **콜백 없이도 순차적인 코드 스타일**로 **비동기 작업**을 작성할 수 있다.
> **코루틴의 특징:**
> - **스레드보다 가벼움** (필요할 때만 실행되고, 자동으로 일시 중단됨)
> - **순차적 스타일로 작성 가능** (콜백 없이 비동기 코드 작성 가능)
> - **비동기 코드가 직관적이고 읽기 쉬움**
---
## **3. 코틀린에서 코루틴 사용하기**
### **3.1. 기본적인 코루틴 사용**
```kotlin
import kotlinx.coroutines.*
fun main() = runBlocking { // 코루틴 블록 시작
launch {
delay(1000L) // 1초 대기
println("코루틴 실행!")
}
println("메인 함수 실행")
}
```
**출력 결과:**
```
메인 함수 실행
코루틴 실행!
```
> - `runBlocking {}`: 메인 함수에서 코루틴을 실행하는 블록
> - `launch {}`: 새로운 코루틴을 실행
> - `delay(1000L)`: 1초 동안 비동기 대기 (스레드 차단 없이 실행 가능)
---
## **4. 코루틴 빌더 (`launch` vs `async`)**
코루틴을 실행할 때는 **`launch`** 와 **`async`** 를 사용할 수 있다.
| 빌더 | 반환값 | 특징 |
|------|------|------|
| `launch` | 없음 (`Job` 반환) | 단순히 코루틴을 실행 |
| `async` | `Deferred<T>` 반환 | 결과 값을 반환하는 비동기 작업 |
### **4.1. `launch` 사용 예시 (결과 값 없음)**
```kotlin
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000L)
println("launch: 비동기 작업 완료!")
}
}
```
> - `launch {}` 는 단순히 비동기 작업을 실행하고, 결과를 반환하지 않음.
> - `Job` 객체를 반환하지만, 보통 `join()`을 호출하지 않는 이상 결과를 기다리지 않음.
---
### **4.2. `async` 사용 예시 (결과 값 반환)**
```kotlin
import kotlinx.coroutines.*
fun main() = runBlocking {
val result = async {
delay(1000L)
"async: 비동기 작업 완료!"
}
println(result.await()) // 결과 값을 기다림
}
```
> - `async {}` 는 **결과 값을 반환하는 비동기 작업**을 실행.
> - `await()` 을 호출해야 실제 값을 가져올 수 있음.
---
## **5. 여러 개의 비동기 작업 실행 (`async` 활용)**
비동기 작업을 병렬로 실행하려면 **`async {}` 를 여러 개 실행**하면 된다.
```kotlin
import kotlinx.coroutines.*
fun main() = runBlocking {
val time = measureTimeMillis {
val job1 = async { fetchData(1) }
val job2 = async { fetchData(2) }
println(job1.await())
println(job2.await())
}
println("총 실행 시간: $time ms")
}
suspend fun fetchData(id: Int): String {
delay(1000L) // 네트워크 요청 시뮬레이션
return "데이터 $id 가져옴"
}
```
**출력 결과:**
```
데이터 1 가져옴
데이터 2 가져옴
총 실행 시간: 1003 ms
```
> - `async {}` 로 실행된 두 개의 코루틴이 **병렬로 실행됨**.
> - `await()` 를 호출하면 해당 코루틴이 완료될 때까지 기다림.
> - 실행 시간은 1초 내외 (동시 실행되었기 때문).
---
## **6. `suspend` 함수 사용하기**
코루틴에서 비동기 함수를 만들려면 **`suspend` 키워드**를 사용해야 한다.
```kotlin
suspend fun fetchData(): String {
delay(1000L) // 1초 대기
return "데이터 가져옴"
}
fun main() = runBlocking {
val data = fetchData()
println(data)
}
```
> - `suspend` 함수는 **코루틴 내에서만 실행 가능**
> - `delay()` 같은 비동기 함수 호출 가능
---
## **7. 예외 처리 (`try-catch` 활용)**
코루틴에서도 **예외 처리를 `try-catch` 로 할 수 있음**.
```kotlin
import kotlinx.coroutines.*
fun main() = runBlocking {
try {
val result = async { errorTask() }.await()
println(result)
} catch (e: Exception) {
println("예외 발생: ${e.message}")
}
}
suspend fun errorTask(): String {
delay(500L)
throw RuntimeException("오류 발생!")
}
```
**출력 결과:**
```
예외 발생: 오류 발생!
```
> - `try-catch` 를 사용하면 **비동기 코드에서도 예외를 안전하게 처리 가능**.
---
## **8. 정리**
| 기능 | 자바 | 코틀린 |
|------|------|------|
| 비동기 실행 | 콜백 기반 | 코루틴 기반 (`launch`, `async`) |
| 가독성 | 콜백 중첩 발생 | 순차적 코드 스타일 |
| 예외 처리 | 예외 전달 어려움 | `try-catch` 사용 가능 |
| 실행 효율 | 스레드 사용 | 가벼운 코루틴 사용 |
> **코루틴을 사용하면:**
> ✅ **비동기 코드가 더 간결하고 직관적**
> ✅ **콜백 지옥 없이 순차적 스타일로 작성 가능**
> ✅ **스레드보다 가볍고 효율적**
코틀린에서 **비동기 프로그래밍을 쉽게 구현하려면 코루틴을 적극 활용하자!** 🚀