code

Kotlin의 async & await 이해하기

sinply 2025. 3. 10. 23:32
반응형
SMALL

코틀린에서 비동기 프로그래밍을 처리하는 대표적인 방식은 코루틴(Coroutines) 을 사용하는 것이야.
특히 async 와 await 를 활용하면 병렬적으로 여러 작업을 수행할 수 있어!

✅ async 와 await 개념

  • async 👉 비동기적으로 실행할 코드 블록을 정의
  • await 👉 해당 비동기 작업이 완료될 때까지 기다림

즉, async 를 사용하면 새로운 코루틴을 실행하고,
await 를 호출하면 그 결과가 나올 때까지 기다릴 수 있어! 🚀


📌 기본 동기 방식과 비교

🔴 동기 방식 예제 (Sequential Execution)

import kotlin.system.measureTimeMillis

fun main() {
    val time = measureTimeMillis {
        val result1 = doSomething()  // 첫 번째 작업
        val result2 = doSomething()  // 두 번째 작업
        println("결과: ${result1 + result2}")
    }
    println("총 소요 시간: ${time}ms")
}

fun doSomething(): Int {
    Thread.sleep(1000) // 1초 대기
    return 10
}
📝 실행 결과
결과: 20  
총 소요 시간: 2004ms

각 작업이 순차적으로 실행되면서 총 2초 이상 소요되는 걸 볼 수 있어. 🐌


🟢 비동기 방식 (async / await) 예제

 
import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis

fun main() = runBlocking {
    val time = measureTimeMillis {
        val deferred1 = async { doSomethingAsync() }  // 첫 번째 비동기 작업
        val deferred2 = async { doSomethingAsync() }  // 두 번째 비동기 작업

        val result = deferred1.await() + deferred2.await() // 결과를 기다림
        println("결과: $result")
    }
    println("총 소요 시간: ${time}ms")
}

suspend fun doSomethingAsync(): Int {
    delay(1000) // 1초 대기 (비동기)
    return 10
}

📝 실행 결과

결과: 20  
총 소요 시간: 1005ms

비동기 방식에서는 두 개의 작업이 동시에 실행되면서 1초만에 끝나는 걸 확인할 수 있어! 🚀


✅ async & await 사용의 장점

비동기 실행

  • 여러 작업을 동시에 실행하므로 시간이 단축돼!

블로킹 없이 실행

  • delay()를 사용하여 블로킹 없이 처리 가능

🚀 빠른 응답 속도

  • async 로 여러 네트워크 요청을 동시에 보낼 수 있어

❌ 단점

코루틴 컨텍스트 관리 필요

  • launch 와 다르게 async 는 반드시 await() 을 호출해야 해!

코루틴 취소 처리 필요

  • 부모 코루틴이 취소될 때, async 로 실행한 작업도 같이 취소하도록 신경 써야 해

🚀 성능 처리 이점

  • 단순한 동기 실행보다 훨씬 빠르게 처리 가능
  • 특히 IO 작업 (네트워크, DB 쿼리 등) 에서 성능 차이가 큼
  • CPU 연산보다 비동기 작업이 효과적
  •  

🚨문제점

1️⃣ 코루틴 생성 비용 (Coroutine Creation Cost)

  • 코루틴을 만들면 내부적으로 컨텍스트 스위칭디스패처 스케줄링이 일어나.
  • 작은 작업이라면, 코루틴을 만드는 비용 > 작업 수행 시간이 되어버려서 오히려 더 느려질 수 있어.

2️⃣ 코루틴 디스패처 (Dispatcher) 오버헤드

  • Dispatchers.Default 나 Dispatchers.IO 같은 디스패처를 사용하면 스레드 풀을 관리하는 비용이 추가돼.
  • 작은 연산에 대해 불필요한 스레드 스위칭이 일어나면, 그냥 동기 실행보다 비효율적일 수 있어.

3️⃣ 추가적인 스코프 관리 비용

  • runBlocking 같은 블로킹 방식으로 실행하면, 메인 스레드가 대기하는 오버헤드가 생길 수 있어.
  • 잘못된 스코프 관리로 메모리 누수도 발생할 가능성이 있음.
반응형
LIST