Coroutine 실행 취소하기

import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch {
        repeat(1000) { i ->
            println("job: I'm sleeping $i ...")
            delay(500L)
        }
    }
    delay(1300L) 
    println("main: I'm tired of waiting!")
    job.cancel() // Job을 cancel한다.
    job.join() // Job의 실행(취소)이 완료될 때까지 기다린다.
		// job.cancelAndJoin()
    println("main: Now I can quit.")
}
cancel을 하고 join을 안해준 경우엔 cancel 이후의 코드가 코루틴이 완전히 종료되기 전에
실행될 가능성이 있음.

Coroutines 취소는 협력적이다

import kotlinx.coroutines.*

fun main() = runBlocking {
    val startTime = System.currentTimeMillis()
    val job = launch(Dispatchers.Default) {
        var nextPrintTime = startTime
        var i = 0
        while (i < 5) { // 계산 루프, CPU를 낭비한다
            // 1초에 두 번 메세지를 출력한다.
            if (System.currentTimeMillis() >= nextPrintTime) {
                println("job: I'm sleeping ${i++} ...")
                nextPrintTime += 500L
            }
        }
    }
    delay(1300L) // 약간의 시간 동안 delay 한다
    println("main: I'm tired of waiting!")
    job.cancelAndJoin() // Job을 취소하고 실행이 완료될 때까지 기다린다.
    println("main: Now I can quit.")    
}

// 이 코드는 취소했음에도 I'm sleeping이 출력되는 이유는 cancel호출시 중단지점이 없음.
출력결과 :
job: I'm sleeping 0 ...
job: I'm sleeping 1 ...
job: I'm sleeping 2 ...
main: I'm tired of waiting!
job: I'm sleeping 3 ...
job: I'm sleeping 4 ...
main: Now I can quit.

위 처럼 취소를 했음에도, I'm sleeping이 계속 출력됨.

위와 같은 문제는 CancellationException을 catch하고 다시 throw 하지 않는 경우에도 발생함.

try {
		... 
} catch (e: CancellationException) {
		throw e
}

Coroutine의 Computation 코드를 취소 가능하게 만들기

// 명시적으로 취소 상태를 확인하는 예시
val job = launch(Dispatchers.Default) {
        var nextPrintTime = startTime
        var i = 0
        while (isActive) { // 취소 가능한 computation loop
            // 1초에 두 번 메세지를 출력한다.
            if (System.currentTimeMillis() >= nextPrintTime) {
                println("job: I'm sleeping ${i++} ...")
                nextPrintTime += 500L
            }
        }
    }