Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

훌륭한 개발자가 되기 위하여

코루틴으로부터 결과 수신 받기 본문

안드로이드

코루틴으로부터 결과 수신 받기

jay20033 2025. 1. 8. 16:18

async-await

async 호출시 코루틴 생성, Deferred<T> 타입의 객체가 반환

async 함수도 launch 함수와 마찬가지로 context 인자로 CoroutineName이나 CoroutineDispatcher 설정 가능

start 인자로 CoroutineStart.LAZY를 설정해 지연 코루틴 생성 가능

async 블록의 반환값으로 반환할 결과값을 설정하면 자동으로 제네릭 타입이 지정됨

fun main() = runBlocking<Unit> {
    // Deferred<String>
    val networkDeferred = async(Dispatchers.IO) {
        delay(1000L)
        return@async "Network Response"
    }
}

 

결과값이 필요한 경우 결과값이 수신될 때까지 대기해야한다.

Deferred 객체의 awiat 함수를 호출하면 Deferred 코루틴이 실행 완료될 때까지 await 함수를 호출한 코루틴이 일시 중단됨

Deferred 코루틴이 실행 완료되면 결과값이 반환되고 호출부의 코루틴이 재개된다.


Deferred와 Job

launch 함수를 호출해 생성한 코루틴은 Job 반환

async 함수를 호출해 생성한 코루틴은 Deferred 반환

👉 Deferred는 Job의 서브타입이며 코루틴으로부터 결과값 수신을 위해 몇 가지 함수만 추가된 인터페이스

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


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

프로그램을 만들 때 여러 비동기 작업으로부터 결과값을 반환받아 병합해야 하는 경우가 자주 생긴다.

👉 복수의 코루틴을 생성해 결과값을 취합해야 한다.

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

fun main() = runBlocking<Unit> {
    val deferred1: Deferred<String> = async(Dispatchers.IO) {
        delay(1000L)
        return@async "Deferred1 result"
    }
    val deferred2: Deferred<String> = async(Dispatchers.IO) {
        delay(1000L)
        return@async "Deferred2 result"
    }

    val result1 = deferred1.await()
    val result2 = deferred2.await()
}

 

awaitAll을 사용하면 복수의 Deferred 객체로부터 결과값을 수신할 수 있다.

awaitAll 함수는 가변 인자로 Deferred 타입의 객체를 받아 인자로 받은 모든 Deferred로부터 결과가 수신될 때까지 호출부의 코루틴을 일시 중단한다.

val result = awaitAll(deferred1, deferred2)

 

 

👉 awaitAll 함수는 Collection에 대한 확장함수로도 선언되어 있다.

val result = listOf(deferred1, deferred2).awaitAll()

withContext 함수

인자로 받은 CoroutineDispatcher를 사용해 코루틴의 실행 스레드를 전환하고, 람다식의 코드를 실행한 후 결과값을 반환하는 함수

👉 람다식을 실행한 후에는 스레드가 다시 이전의 Dispatcher을 사용하도록 전환한다.

fun main() = runBlocking<Unit> {
    val result = withContext(Dispatchers.IO) {
        delay(1000L)
        println("[${Thread.currentThread().name}] 결과값이 반환됩니다.")
        "결과값"
    }
    println("$result")
}
// 실행 결과
[DefaultDispatcher-worker-1 @coroutine#1] 결과값이 반환됩니다.
[main @coroutine#1] 결과값

 

async는 코루틴을 생성하고 blocking 코루틴이 default 코루틴이 완료할 때까지 대기함

withContext는 인자로 받은 디스패처를 사용해 코루틴의 실행, 쓰레드를 전환하여 결국 코루틴이 유지되어 순차처리되는 것이지 새로운 코루틴을 실행하는게 아님

fun main() = runBlocking<Unit> {
    val result1 = withContext(Dispatchers.IO) {
        delay(1000L)
        println("[${Thread.currentThread().name}] 결과값이 반환됩니다.")
        "결과값1"
    }

    val result2 = withContext(Dispatchers.IO) {
        delay(1000L)
        println("[${Thread.currentThread().name}] 결과값이 반환됩니다.")
        "결과값2"
    }

    val results = listOf(result1, result2)
    println("$results")
}

 

withContext는 병렬적으로 처리되지 않고 코루틴이 유지된 상태로 스레드만 바뀌기 때문에 순차 처리됨

👉 병렬적으로 처리를 해야할 경우 async 함수를 사용해야함

'안드로이드' 카테고리의 다른 글

구조화된 동시성  (0) 2025.01.11
CoroutineContext란  (0) 2025.01.10
코루틴 제어  (0) 2025.01.07
스레드 기반 작업의 한계, Coroutine Dispatcher  (0) 2025.01.06
[Android] Ktlint적용하기  (0) 2024.10.29