ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • async-await
    BackEnd/coroutine 2025. 6. 8. 05:00
    반응형

    async와 Deferred

    • async 코루틴 빌더를 호출하면 코루틴이 생성되고, Deferred<T> 타입 객체가 반환됩니다.
    • Deferred는 Job과 같이 코루틴을 추상화한 객체이지만, 코루틴으로부터 생성된 결과값을 감싸는 기능을 추가로 가집니다.
    • 결과값의 타입은 제네릭 타입인 T로 표현됩니다.
    public fun <T> CoroutineScope.async(
        context: CoroutineContext = EmptyCoroutineContext,
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> T
    ): Deferred<T>

     

    async vs launch

    • async 함수도 launch 함수와 마찬가지로
      1. context 인자로 CoroutineName이나 CoroutineDispatcher 설정이 가능합니다.
      2. start 인자로 CoroutineStart.LAZY를 설정해 지연 코루틴을 만들 수 있습니다.
    • async 함수가 launch 함수와 다른 점은 block 람다식이 T를 반환한다는 점과 반환 객체가 Deferred라는 점입니다.
    public fun <T> CoroutineScope.launch(
        context: CoroutineContext = EmptyCoroutineContext,
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> Unit
    ): Job

     

    Deferred

    • Deferred는 Job의 서브타입으로, 코루틴으로부터의 결과값 수신을 위해 몇가지 함수만 추가된 인터페이스입니다.
    public interface Deferred<out T> : Job

     

    • Deferred 객체는 Job 객체의 모든 함수와 프로퍼티를 사용할 수 있습니다.

     

    Deferred 객체의 제네릭 타입 지정

      Deferred 객체의 제네릭 타입을 지정하기 위해서는 Deferred에 명시적으로 타입을 설정하고, async 람다식에 반환값을 설정하면 됩니다.

    import kotlinx.coroutines.*
    
    fun main() = runBlocking<Unit> {
        val networkDeferred = async(Dispatchers.IO) {
            delay(1000L) // 네트워크 요청
            return@async "Dummy Response" // Dummy Response 반환
        }
    }

     

    Deferred 객체의 동작 방식

    • Deferred 객체는 미래의 어느 시점에 결과값이 반환될 수 있음을 표현하는 코루틴 객체입니다.
    • 코루틴이 실행 완료되었을 때 결과값이 반환되므로 언제 수신될 지 알 수 없습니다.
    • 결과값이 필요하다면 결과값이 수신될 때까지 대기해야 합니다.
    • Deferred 객체의 await 함수를 호출하면 Deferred 코루틴이 실행 완료될 때까지 await 함수를 호출한 코루틴이 일시 중단됩니다.
    • Deferred 코루틴이 실행 완료되면 결과값이 반환되고 호출부의 코루틴이 재개됩니다.
    import kotlinx.coroutines.*
    
    fun main() = runBlocking<Unit> {
        val networkDeferred: Deferred<String> = async(Dispatchers.IO) {
            delay(1000L) // 네트워크 요청
            return@async "Dummy Response" // Dummy Response 반환
        }
        val result = networkDeferred.await() // 결과값이 반환될 때까지 runBlocking 일시 중단
        println(result) // 결과값 출력
    }

     

    복수의 코루틴으로부터 결과값 수신하기

      다음 코드는 두 개의 코루틴을 실행하고 결과를 수신하는 예제입니다. 코드를 실행하여 출력 결과를 확인해보면 순차적으로 실행된 것을 확인할 수 있습니다. 이는 async-await이 연속적으로 호출됐기 때문입니다.

    import kotlinx.coroutines.*
    
    fun main() = runBlocking<Unit> {
        val startTime = System.currentTimeMillis() // 1. 시작 시간 기록
    
        // 2. 플랫폼1에서 등록한 관람객 목록을 가져오는 코루틴 실행
        val participantDeferred1: Deferred<Array<String>> = async(Dispatchers.IO) {
            delay(1000L)
            return@async arrayOf("철수","영수")
        }
        val participants1 = participantDeferred1.await() // 3. 결과가 수신 될 때까지 대기
    
        // 4. 플랫폼2에서 등록한 관람객 목록을 가져오는 코루틴 실행
        val participantDeferred2: Deferred<Array<String>> = async(Dispatchers.IO) {
            delay(1000L)
            return@async arrayOf("영희")
        }
        val participants2 = participantDeferred2.await() // 5. 결과가 수신 될 때까지 대기
    
        // 6. 지난 시간 표시 및 참여자 목록을 병합해 출력
        println("[${getElapsedTime(startTime)}] 참여자 목록: ${listOf(*participants1, *participants2)}")
    }
    
    fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
    // 출력 결과
    [지난 시간: 2024ms] 참여자 목록: [철수, 영수, 영희]

     

      코루틴을 병렬로 실행하기 위해서는 코루틴을 모두 실행한 다음 await을 호출해야 합니다.

    import kotlinx.coroutines.*
    
    fun main() = runBlocking<Unit> {
        val startTime = System.currentTimeMillis() // 1. 시작 시간 기록
    
        // 2. 플랫폼1에서 등록한 관람객 목록을 가져오는 코루틴 실행
        val participantDeferred1: Deferred<Array<String>> = async(Dispatchers.IO) {
            delay(1000L)
            return@async arrayOf("철수","영수")
        }
    
        // 3. 플랫폼2에서 등록한 관람객 목록을 가져오는 코루틴 실행
        val participantDeferred2: Deferred<Array<String>> = async(Dispatchers.IO) {
            delay(1000L)
            return@async arrayOf("영희")
        }
    
        val participants1 = participantDeferred1.await() // 4. 결과가 수신 될 때까지 대기
        val participants2 = participantDeferred2.await() // 5. 결과가 수신 될 때까지 대기
    
        // 6. 지난 시간 표시 및 참여자 목록을 병합해 출력
        println("[${getElapsedTime(startTime)}] 참여자 목록: ${listOf(*participants1, *participants2)}")
    }
    
    private fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"
    // 출력 결과
    [지난 시간: 1014ms] 참여자 목록: [철수, 영수, 영희]

     

    awaitAll 함수

    • awaitAll을 사용하면 복수의 Deferred 객체로부터 결과값을 수신할 수 있습니다.
    • awaitAll 함수는 가변 인자로 Deferred 타입의 객체를 받아 인자로 받은 모든 Deferred로부터 결과가 수신될 때까지 호출부의 코루틴을 일시 중단합니다.
    import kotlinx.coroutines.*
    
    fun main() = runBlocking<Unit> {
        val startTime = System.currentTimeMillis() // 1. 시작 시간 기록
    
        // 2. 플랫폼1에서 등록한 관람객 목록을 가져오는 코루틴 실행
        val participantDeferred1: Deferred<Array<String>> = async(Dispatchers.IO) {
            delay(1000L)
            return@async arrayOf("철수", "영수")
        }
    
        // 3. 플랫폼2에서 등록한 관람객 목록을 가져오는 코루틴 실행
        val participantDeferred2: Deferred<Array<String>> = async(Dispatchers.IO) {
            delay(1000L)
            return@async arrayOf("영희")
        }
    
        // 4. 두 개의 코루틴으로부터 결과가 수신될 때까지 대기
        val results = awaitAll(participantDeferred1, participantDeferred2)
        // val results = listOf(participantDeferred1, participantDeferred2).awaitAll() // Collection 확장함수
    
        // 5. 지난 시간 표시 및 참여자 목록을 병합해 출력
        println("[${getElapsedTime(startTime)}] 참여자 목록: ${listOf(*results[0], *results[1])}")
    }
    
    private fun getElapsedTime(startTime: Long): String = "지난 시간: ${System.currentTimeMillis() - startTime}ms"

     

    반응형

    'BackEnd > coroutine' 카테고리의 다른 글

    CoroutineContext  (1) 2025.06.15
    withContext  (0) 2025.06.14
    Coroutine 상태  (1) 2025.06.07
    Coroutine 취소  (0) 2025.06.01
    지연 Coroutine  (0) 2025.05.31

    댓글

Designed by Tistory.