KOTLIN

[KOTLIN] CANCELLATION (취소)

집한구석 2022. 6. 9. 20:41
728x90

Cancellation 

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 취소
    job.join() // job의 완료를 기다림.
    println("main: Now I can quit.")
    // 끝
}
  • 코루틴을 사용할 경우 더이상 코루틴 동작이 필요하지 않은 경우 취소를 해줘야함 (자원 낭비가 발생)
  • main()에서 job.cancel을 호출하면 다른 코루틴이 취소 되기 때문에 출력 금지됨

Cancellation is cooperative

fun main() = runBlocking {
    // 시작
    val startTime = System.currentTimeMillis()
    val job = launch(Dispatchers.Default) {
        var nextPrintTime = startTime
        var i = 0
        while (i < 5) { // 연산 루프, CPU를 소비한다.
            // 초당 두 번씩 메시지를 출력한다.
            if (System.currentTimeMillis() >= nextPrintTime) {
                println("job: I'm sleeping ${i++} ...")
                nextPrintTime += 500L
            }
        }
    }
    delay(1300L) // 조금 지연시킴
    println("main: I'm tired of waiting!")
    job.cancelAndJoin() // job을 취소하고 완료되기를 기다림
    println("main: Now I can quit.")
    // 끝    
}

 

  • 코루틴의 취소는 협조적이며, 코루틴의 모든 suspend 함수는 취소가 가능함
  • 취소를 확인한후 CancellationException이 발생, 코루틴이 연산 작업인 경우에는 취소 여부를 확인하지 않으면 취소를 할 수 없음

연산 코드 취소

fun main() = runBlocking {
    //시작
    val startTime = System.currentTimeMillis()
    val job = launch(Dispatchers.Default) {
        var nextPrintTime = startTime
        var i = 0
        while (isActive) { // 취소 가능한 연산 루프
            if (System.currentTimeMillis() >= nextPrintTime) {
                println("job: I'm sleeping ${i++} ...")
                nextPrintTime += 500L
            }
        }
    }
    delay(1300L) 
    println("main: I'm tired of waiting!")
    job.cancelAndJoin()
    println("main: Now I can quit.")
    // 끝    
}
  • isActive를 통하여 코루틴스코프 객체를 통해 연산 루프를 취소 
  • isActive는 job이 active 상태인지 체크 해줌

Closing resources with finally

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) 
    println("main: I'm tired of waiting!")
    job.cancelAndJoin() 
    println("main: Now I can quit.")
    // 끝
}
  • try finally를 이용하여 코틀린이 취소될 때 정상적으로 최종작업을 진행
  • finally는 리소스 해제 지역임, finally 블록에서 suspend함수를 사용하려고 하면 CancellationException 발생함

Non-cancellable block

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) 
    println("main: I'm tired of waiting!")
    job.cancelAndJoin() 
    println("main: Now I can quit.")
}
  • 취소된 코루틴에서 suspend 함수를 사용해야하는 경우 withContext(NonCancellable)로 감싸서 사용이 가능함 

'KOTLIN' 카테고리의 다른 글

[KOTLIN] 변수의 스코프 최소화 (이펙티브코틀린)  (0) 2022.06.18
[KOTLIN] CONTEXT / DISPATCHER  (0) 2022.06.15
[KOTLIN] SUSPEND 함수  (0) 2022.06.06
[KOTLIN] 코루틴  (0) 2022.06.01
[KOTLIN] NULL SAFTY / NULL 처리방법  (0) 2022.05.30