Coroutines와 Threads 디버깅 하기
Coroutines는 하나의 스레드에서 일시 중단한 다음 다른 스레드에서 재개될 수 있다. 싱글 스레드를 가진 Dispatcher에서도 특별한 도구가 없으면 Coroutine이 언제, 어디서 무엇을 하는지 알기 어렵다.*1
IDEA를 사용해 디버깅 하기
Kotlin Plugin인 Coroutine Debugger은 Intellij IDEA에서 Coroutines 디버깅을 간단하게 할 수 있도록 한다.
📍 디버깅은 kotlinx-coroutines-core 1.3.8 혹은 그 이후 버전에서부터만 동작한다.
Debug tool window는 Coroutines 탭을 포함한다. 이 탭에서 현재 실행 중이거나 일시 중단된 Coroutine 모두에 대한 정보를 확인할 수 있다. Coroutines 는 실행 중인 Dispatcher에 따라 그룹화된다.
Coroutine Debugger을 사용해서 이런 것들을 할 수 있다 :
- 각 Coroutine에 대한 상태를 확인할 수 있다.
- 실행 중이거나 일시 중단된 Coroutines에 대한 지역 변수나 캡처된 변수의 값들을 확인할 수 있다..
- Coroutine 생성 스택뿐만 아니라, Coroutine 내부의 콜스택에 대한 확인 할 수 있다. 스택은 일반적인 디버깅에서 손실되는 프레임을 포함한 전체 프레임들에 대한 변수의 값들을 포함한다.
- 각 Coroutine의 상태와 그 스택들을 포함하는 전체 리포트를 가져올 수 있다. 이것을 얻기 위해서는 Coroutines Tab을 마우스 우클릭 후, Get Coroutines Dump를 클릭하면 된다.
Coroutine 디버깅을 시작하기 위해서는, Breakpoint들을 설정하고 어플리케이션을 디버그 모드로 실행하면 된다.
Coroutine 디버깅에 대해 튜토리얼에서 더 알아볼 수 있다.
로깅을 통해 디버깅 하기
Coroutine Debugger 없이 스레드를 사용하는 어플리케이션을 디버깅하는 방법은 각 로그 구문에 스레드 이름을 넣어, 로그 파일에 스레드 이름을 인쇄하는 것이다. 이 기능은 로깅 프레임워크들에서 보편적으로 지원한다. Coroutines를 사용할 때 스레드 이름만으로는 Context에 대한 많은 정보들을 제공하지 않으므로, kotlinx.coroutines 는 디버깅을 쉽게 하기 위한 많은 기능들을 포함한다.
JVM 옵션에 -Dkotlinx.coroutines.debug 를 포함한 채로 다음 코드를 실행해보자.
import kotlinx.coroutines.*
fun log(msg: String) = println("[${Thread.currentThread().name}] $msg")
fun main() = runBlocking<Unit> {
val a = async {
log("I'm computing a piece of the answer")
6
}
val b = async {
log("I'm computing another piece of the answer")
7
}
log("The answer is ${a.await() * b.await()}")
}
📌 전체 코드는 이곳에서 확인할 수 있습니다.
이 코드에는 3 개의 Coroutine이 있다. runBlocking 속의 main Coroutine(#1)과 지연된 값 a(#2)와 b(#3)를 계산하는 두 Coroutine들이다. 이들은 모두 runBlocking의 Context에서 실행되며, 이들은 모두 Main Thread에서 실행되도록 제한된다. 이 코드의 출력은 다음과 같다 :
[main @coroutine#2] I'm computing a piece of the answer
[main @coroutine#3] I'm computing another piece of the answer
[main @coroutine#1] The answer is 42
log 함수는 대괄호들 내부의 스레드의 이름을 출력하며, 현재 실행중인 Coroutine에 추가된 식별자는 main 스레드임을 알 수 있다. 이 식별자는 디버깅 모드가 켜져 있을 때 생성된 모든 Coroutine들에 연속적으로 할당된다.
📖 디버깅 모드는 JVM이 -ea 옵션이 포함된 채로 실행될 때 켜진다. 디버깅 기능들에 대한 추가적인 것들은 DEBUG_PROPERTY_NAME 프로퍼티에 대한 문서에서 확인할 수 있다.
📖 아래 내용은 독자의 이해를 위해 번역자가 추가한 글입니다.
*예를 들어 Single Thread를 관리하는 Dispatcher에서 delay를 하게 되면 delay는 Dispatcher에서 관리하는 스레드가 아닌 Default Executor Thread에서 실행된다. 이와 같이 내부에서 별도의 Dispatcher을 지정해 Job을 수행할 수 있도록 할 수 있기 때문에 알기 어렵다.
이 글은 Coroutines 공식 문서를 번역한 글입니다.
원문 : Coroutine context and dispatchers - Debugging coroutines and threads
원문 최종 수정 : 2022년 6월 27일