본문 바로가기
✔️ Kotlin

Coroutine이 취소되는 기본 동작 방식

by iirin 2024. 5. 25.

코루틴의 취소

코루틴은 실행 중에 취소 요청에 의해 취소되거나 예외가 발생하여 취소될 수 있습니다.

코루틴이 취소되는 것이 중요한 이유는 필요하지 않은 코루틴을 적절하게 취소하여 컴퓨팅 자원을 효율적으로 사용하는 것이 중요하기 때문입니다.

그러나 바로 스레드를 죽이는 것은 좋지 않은 해결방법입니다. 스레드에서 활용중이던 리소스 연결을 먼저 해제한 후 취소하는 것이 더 우아한 방법이겠죠?

 

취소하는 방법

코루틴을 취소하는 기본적인 방법은 `cancel` 함수를 사용하는 방법입니다.

이 함수를 사용하면 이런 특징을 가지고 있습니다.

  • 취소 시점으로부터 첫번째 중단 지점(suspend 함수 사용 지점)부터 취소가 이루어집니다.
  • 하위 job이 있는 경우 모두 취소합니다.
suspend fun main(): Unit = coroutineScope {
   val job = launch {
       // job work
   }
   job.cancel()
   job.join() // 혹은 cancelAndJoin()
}

 

 

위의 특징에서도 보이듯이 `cancel()` 함수만으로 코루틴을 중단할 수는 없습니다.

취소 여부 체크를 하기 위해 중단 지점으로 인위적으로 `delay()`, `yield()` 같은 coroutines 패키지의 `suspend` 함수를 사용합니다.

만약 이런 suspend 패키지의 함수를 사용하지 않았다면 취소가 이루어지지 않습니다. 해당 코루틴의 동작이 모두 수행되고나서야 취소됩니다.

 

👀 어떻게 취소되는 거지? `Cancellation Exception`

사실 코루틴이 멈추는 모든 로직은 이 예외를 발생시켜 멈춥니다.

따라서 `Cancellation Exception` 을 try-catch 한다면 코루틴은 멈추지 않습니다. 혹은 `Cancellation Exception` 를 상속받은 다른 예외를 통해 코루틴을 멈출 수도 있습니다.

코루틴은 중단지점마다 본인의 상태를 확인해 취소 요청을 받으면 그냥 중지되는 것이 아니라  내부적으로 `Cancellation Exception` 를 던집니다.

 

val job = lanch(Dispatchers.Default) {
	if (isActive) { // 취소 신호가 있는지 확인할 수 있습니다.
		throw CancellationException()
	}
}

// ---

job.cancel()

 

 

 

코루틴이 `CancellationException`과 일반 예외를 처리하는 차이

발생한 예외가 `CancellationException`이라면 취소 요청으로 간주하고 부모 코루틴에게 전파하지 않습니다.

다만 그 이외의 예외가 발생한 경우 코루틴 실행 실패로 간주하고 부모 코루틴에게 전파합니다.

내부적으로는 두 가지 케이스 모두 '취소됨'으로 관리합니다. 즉, `CancellationException` 을 던집니다.