막무가내 삽질 블로그

코루틴 제어 본문

Android

코루틴 제어

joong~ 2020. 5. 10. 22:41
728x90

코루틴을 잘활용할려면 결과를 반환 받아서 처리를 하고 작업의 취소까지도 완벽하게 해줘야한다.

 

 

fun main() = runBlocking {
    val job = launch {
        repeat(1000) { i ->
            println("job: I'm sleeping $i ...")
            delay(500L)
        }
    }
    delay(1300L) // delay a bit
    println("main: I'm tired of waiting!")
    job.cancel() // cancels the job
    job.join() // waits for job's completion 
    println("main: Now I can quit.")    
}

0.5초 간격으로 문자열을 1000회 출력하는 블록이다. 블록이 시작한 후 1.3초가 지나면 코루틴을 취소한다.

 

 

 

fun main() = runBlocking {
    val startTime = System.currentTimeMillis()
    val job = launch(Dispatchers.Default) {
        var nextPrintTime = startTime
        var i = 0
        while (i < 10) { // computation loop, just wastes CPU
            // print a message twice a second
            if (System.currentTimeMillis() >= nextPrintTime) {
                println("job: I'm sleeping ${i++} ...")
                nextPrintTime += 500L
            }
        }
    }
    delay(1300L) // delay a bit
    println("main: I'm tired of waiting!")
    job.cancelAndJoin() // cancels the job and waits for its completion
    println("main: Now I can quit.")
}

1.3초가 지난 후에 코루틴 블록이 해제가 되어야 하지만 cancelAndJoin함수로 인해 블록이 완료될때 까지 기다렸다 종료가 된걸 확인할 수 있다.

 

 

fun main() = runBlocking {
    val startTime = System.currentTimeMillis()
    val job = launch(Dispatchers.Default) {
        var nextPrintTime = startTime
        var i = 0
        while (isActive) { // cancellable computation loop
            // print a message twice a second
            if (System.currentTimeMillis() >= nextPrintTime) {
                println("job: I'm sleeping ${i++} ...")
                nextPrintTime += 500L
            }
        }
    }
    delay(1300L) // delay a bit
    println("main: I'm tired of waiting!")
    job.cancelAndJoin() // cancels the job and waits for its completion
    println("main: Now I can quit.")
}

CoroutineScope의 확장 프로퍼티 isActive로 사용하여 코루틴의 취소 여부를 확인할 수 있다.

 

 

 

fun main() = runBlocking {
    val job = launch {
        try {
            repeat(1000) { i ->
                println("job: I'm sleeping $i ...")
                delay(500L)
            }
        } finally {
            println("job: I'm running finally")
        }
    }
    delay(1300L) // delay a bit
    println("main: I'm tired of waiting!")
    job.cancelAndJoin() // cancels the job and waits for its completion
    println("main: Now I can quit.")    
}

try-finallyfh 블록을 처리하면 종료될 때 finally블록이 실행되는 걸 볼 수 있다.

 

 

fun main() = runBlocking {
    val job = launch {
        try {
            repeat(1000) { i ->
                println("job: I'm sleeping $i ...")
                delay(500L)
            }
        } finally {
            withContext(NonCancellable) {
                println("job: I'm running finally")
                delay(1000L)
                println("job: And I've just delayed for 1 sec because I'm non-cancellable")
            }
        }
    }
    delay(1300L) // delay a bit
    println("main: I'm tired of waiting!")
    job.cancelAndJoin() // cancels the job and waits for its completion
    println("main: Now I can quit.")    
}

만약 finally에서 리소스 사용이 완료될때 까지 대기 해야 한다고하면 delay함수로 사용하면 안된다. 이유는 코루틴 블록 취소에 영향을 받기 때문에 withContext()함수를 사용해야한다.

 

 

fun main() = runBlocking {
    withTimeout(1300L) {
        repeat(1000) { i ->
            println("I'm sleeping $i ...")
            delay(500L)
        }
    }
}

withTimeout() 함수를 사용해 작업을 취소할 수도 있다. 하지만 이 코드를 사용하면 CancellationException이 발생하기 때문에 앱이 강제로 중지된다. 따라서 withTimeoutOrNull()함수를 사용하는 것이 좋다.

 

fun main() = runBlocking {
    val result = withTimeoutOrNull(1300L) {
        repeat(1000) { i ->
            println("I'm sleeping $i ...")
            delay(500L)
        }
        "Done" // will get cancelled before it produces this result
    }
    println("Result is $result")
}
Comments