-
Kotlin Coroutines(3)Kotlin 2021. 5. 27. 10:50
코루틴 블록 취소
delay() 함수 사용
delay() 함수에서 취소가 동작하고 코루틴 블록을 취소할수가 있다.
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.join() println("main: Now I can quit.") }
결과
job: I'm sleeping 0 ... job: I'm sleeping 1 ... job: I'm sleeping 2 ... main: I'm tired of waiting! main: Now I can quit.
yield() 함수 사용
fun main() = runBlocking { val startTime = System.currentTimeMillis() val job = launch(Dispatchers.Default) { var nextPrintTime = startTime var i = 0 while (i < 10) { yield() 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.") }
결과
job: I'm sleeping 0 ... job: I'm sleeping 1 ... job: I'm sleeping 2 ... main: I'm tired of waiting! main: Now I can quit.
yield() 함수를 사용하지 않고 실행해 보면 취소되지 않고 10회 모두 수행 후에 종료된다.
결과
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 ... job: I'm sleeping 5 ... job: I'm sleeping 6 ... job: I'm sleeping 7 ... job: I'm sleeping 8 ... job: I'm sleeping 9 ... main: Now I can quit.
CoroutineScope 의 확장 프로퍼티 isActive 로 확인
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.") }
결과
job: I'm sleeping 0 ... job: I'm sleeping 1 ... job: I'm sleeping 2 ... main: I'm tired of waiting! main: Now I can quit.
try-finally 문으로 리소스 닫기
try-finally 문으로 코루틴 블록을 감싸면, 작업을 종료할때 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) // 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.") }
결과
job: I'm sleeping 0 ... job: I'm sleeping 1 ... job: I'm sleeping 2 ... main: I'm tired of waiting! job: I'm running finally main: Now I can quit.
Run non-cancellable block
finally 블록에서 suspending function(중지함수)을 사용하려고하면 코루틴 블록의 취소에 영향을 받기 때문에 CancellationException이 발생한다.
정상적으로 작동하는 모든 닫기 작업 (파일 닫기, 작업 취소 또는 모든 종류의 통신 채널 닫기)은 일반적으로 차단되지 않으며 일시 중지 기능이 포함되지 않기 때문에 일반적으로 문제가 되지 않는다. 그러나 드물게 취소된 코루틴에서 일시 중지해야하는 경우 withContext() 및 NonCancellable context를 사용한다.
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.") }
결과
job: I'm sleeping 0 ... job: I'm sleeping 1 ... job: I'm sleeping 2 ... main: I'm tired of waiting! job: I'm running finally job: And I've just delayed for 1 sec because I'm non-cancellable main: Now I can quit.
Timeouts - 일정시간 이후 자동 취소 되는 코루틴 블록 만들기
withTimeout() 함수 사용
withTimeout() 함수는 첫번째 인자로 작업을 수행할 시간, 두번째 인자로 수행할 블록 함수를 받는다.
fun main() = runBlocking { withTimeout(1300L) { repeat(1000) { i -> println("I'm sleeping $i ...") delay(500L) } } }
결과
I'm sleeping 0 ... I'm sleeping 1 ... I'm sleeping 2 ... Exception in thread "main" kotlinx.coroutines.TimeoutCancellationException: Timed out waiting for 1300 ms
withTimeout에 의해 throw되는 TimeoutCancellationException은 CancellationException의 하위 클래스이다.
withTimeoutOrNull() 함수 사용
시간 제한에 대해 추가 작업을 수행해야하는 경우 withTimeout과 비슷하지만 시간 초과시 null을 반환하는 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") }
결과
I'm sleeping 0 ... I'm sleeping 1 ... I'm sleeping 2 ... Result is null
References
'Kotlin' 카테고리의 다른 글
Kotlin Coroutines(2) (0) 2021.05.26 Kotlin Coroutines(1) (0) 2021.05.22