Kotlin

Kotlin Coroutines(2)

smomo 2021. 5. 26. 14:35

코루틴 제어

코루틴을 시작하는 방법은 두 가지가 있으며 용도가 다릅니다

 

launch() 함수로 시작된 코루틴 블록은 Job 객체를 반환, 결과값을 반환하지 않는다.

async() 함수로 시작된 코루틴 블록은 Deferred<T>를 반환, await라는 일시 중지 함수로 결과를 반환한다

launch() - Job

반환받은 Job 객체로 코루틴 블록을 취소하거나, 다음 작업의 수행전 코루틴 블록이 완료 되기를 기다릴수 있다.

fun main() = runBlocking {
    val job = launch { // launch a new coroutine and keep a reference to its Job
        delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
        println("World!")
    }
    println("Hello")
    job.join() // wait until child coroutine completes
    println("Done") 
}

결과

 Hello
 World!
 Done

여러개의 launch 코루틴 블록을 실행할 경우 각각의 Job 객체에 대해서 join() 함수로 코루틴 블록이 완료 될때까지 다음 코드 수행을 대기할수 있다.

fun main() = runBlocking {
   val job1 : Job = launch {		
        delay(2000L)
        println("JOB_1")
    }

    val job2 = launch {		
        delay(1000L)
        println("JOB_2")
    }

    job1.join() // wait until child coroutine completes
    job2.join()
    println("Done")           
}

결과

 JOB_2
 JOB_1
 Done

모든 Job 객체에 대해서 일일히 join() 함수를 호출하지 않고 joinAll() 함수를 이용하여 모든 launch 코루틴 블록이 완료 되기를 기다릴수도 있다.

joinAll(job1, job2)

CoroutineScope Builder로 여러 작업을 동시에 수행하기

// doWorld 다음에 "Done"을 차례로 실행
fun main() = runBlocking {
    doWorld()
    println("Done")
}

// 두 sections을 동시에 실행
suspend fun doWorld() = coroutineScope { // this: CoroutineScope
    launch {
        delay(2000L)
        println("World 2")
    }
    launch {
        delay(1000L)
        println("World 1")
    }
    println("Hello")
}

결과

 Hello
 World 1
 World 2
 Done

async() - Deferred

async() 함수로 시작된 코루틴 블록은 Deferred 객체를 반환한다.

fun main() = runBlocking {
    val deferred : Deferred<String> = async {
	delay(2000L)
        "result"
    }
    val msg = deferred.await()
    println(msg) //print result
}

여러 개의 async 코루틴 블록에 같은 Deferred 객체를 사용하는 경우 await() 함수 호출시 전달되는 최종적인 결과값은 첫번째 async 코루틴 블록의 결과값 만을 전달한다.

fun main() = runBlocking {
    val deferred : Deferred<String> = async { 		
        delay(2000L)
        "result1"
    }
    
    async(deferred){
        delay(1000L)
        "result2"
    }
    
    val msg = deferred.await()
    println(msg) //첫번째 블록 결과인 result1 출력
}

runBlocking()

runBlocking() 함수로 시작된 블록은 작업이 완료하기까지 스레드를 점유, 대기한다.

주의해야 할 점은 runBlocking() 코루틴 블록이 사용하는 스레드는 runBlocking() 함수가 호출된 스레드가 된다는 점이다. 안드로이드의 경우 메인 스레드(UI 스레드)에서 호출하여 오래 걸리는 작업을 실행할 경우 ANR이 발생할 위험이 있다.

 

References