티스토리 뷰
요즘 Coroutines는 좀 더 심도있게 공부하기 위해 온라인 강좌를 듣고 있는 중이다. 강좌가 진행되면 될수록 드는 생각이지만 Kotlin Coroutines는 생각만큼 단순하지 않다는 것이다. 아니 상당히 까다로운 프레임웤이라는 것이다. 주된 이유는 내부 메카니즘의 복잡함에 있다고 할 수 있는데, 특히 Cancellation과 Exception Handling으로 들어가면 직관적이지 않은 동작 때문에 Coroutines가 어떻게 동작하는지 정확한 이해가 없을 경우 정말로 골치아픈 버그를 접하게 될 가능성이 많다는 점이다. 예를 하나만 들어보자.
class CoroutineTest {
@Test
fun exceptionTest() {
runBlocking {
val scopeJob = Job()
val scope = CoroutineScope(scopeJob + Dispatchers.Default)
val job1 = scope.launch {
delay(100)
println("inside coroutine")
}
val job2 = scope.launch {
delay(50)
throw RuntimeException()
}
joinAll(job1, job2)
println("scopeJob: $scopeJob")
println("job1: $job1")
println("job2: $job2")
}
Thread.sleep(100)
println("test completed")
}
}
job2에서 Exception을 던지고 있다. 예외처리를 위해, try catch를 사용해 보자.
class CoroutineTest {
@Test
fun exceptionTest() {
runBlocking {
val scopeJob = Job()
val scope = CoroutineScope(scopeJob + Dispatchers.Default)
val job1 = scope.launch {
delay(100)
println("inside coroutine")
}
try {
val job2 = scope.launch {
delay(50)
throw RuntimeException()
}
joinAll(job1, job2)
println("scopeJob: $scopeJob")
println("job1: $job1")
println("job2: $job2")
} catch (e: RuntimeException) {
println("Caught exception: $e")
}
}
Thread.sleep(100)
println("test completed")
}
}
위의 코드를 실행해 보면, 출력결과는 다음과 같다.
at xxx$uncaughtExceptionInConcurrentCoroutinesWithLaunch$1$job2$1.invokeSuspend(CoroutineExceptionHandlerDemoTest.kt:22)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
scopeJob: JobImpl{Cancelled}@57829d67
job1: "coroutine#2":StandaloneCoroutine{Cancelled}@19dfb72a
job2: "coroutine#3":StandaloneCoroutine{Cancelled}@17c68925
test completed
Process finished with exit code 0
위의 예제는 코루틴에서 예외 처리가 생각처럼 직관적이지 않은 것을 보여주기 위한 목적이라 실제로는 저런 코드를 쓰지 않을 거라고 생각할 수도 있을 것이다. 하지만, 여기서의 포인트는 우리가 일반적으로 생각하는 코틀린의 예외처리가 그래도 적용되지 않는다는 데에 있다. 이건 Cancellation 에도 비슷하게 적용된다. 따라서 Coroutines에는 우가 알아야만 대처할 수 있는 동작방식이 존재한다. 앞으로 몇 번의 연재를 통해 코틀린의 전반과 내부동작에 대해 살펴보고, 실전에서 쉽게 마주칠 수 있는 골치아픈 상황을 어떻게 피해갈 수 있는지 배워보기로 하자.
'Kotlin > Coroutines' 카테고리의 다른 글
안드로이드 쓰레드 예제 몇가지 (0) | 2021.03.24 |
---|---|
Android startActivityForResult를 직관적으로 만들기 (3) | 2019.12.08 |
댓글