티스토리 뷰

728x90

6. 코루틴 취소 및 타임아웃

6.1 코루틴 취소 (Cancellation)

코루틴은 비동기적으로 동작하므로, 때로는 진행 중인 작업을 중단해야 할 필요가 있습니다. 코루틴을 취소하는 것은 중요한 작업이며, 취소된 코루틴은 즉시 중단되지만 정리 작업(clean-up)을 할 수 있는 기회도 제공합니다.

코루틴의 취소는 협력적으로 이루어집니다. 이는 코루틴이 명시적으로 취소 상태를 확인하거나, 취소 가능한 함수(delay, yield 등)를 호출할 때만 취소된다는 뜻입니다.

코루틴 취소의 기본 사용 예제

import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch {
        repeat(1000) { i ->
            println("Job: I'm working on $i ...")
            delay(500L)  // `delay`는 취소 가능한 함수
        }
    }

    delay(1300L)  // 잠시 기다렸다가
    println("Main: I'm tired of waiting!")
    job.cancel()  // 코루틴을 취소
    job.join()  // 코루틴이 완전히 종료될 때까지 기다림
    println("Main: Now I can quit.")
}

설명:

  • launch는 비동기 작업을 시작하고, repeat 블록 내에서 반복 작업을 수행합니다.
  • delay취소 가능한 함수로, 취소가 요청되면 코루틴이 중단됩니다.
  • job.cancel()로 코루틴을 취소하고, job.join()으로 코루틴이 완료될 때까지 기다립니다.

출력:

Job: I'm working on 0 ...
Job: I'm working on 1 ...
Job: I'm working on 2 ...
Main: I'm tired of waiting!
Main: Now I can quit.

요점:

  • 코루틴 취소는 협력적으로 이루어집니다. 취소 요청을 받은 후에도 코루틴이 취소 가능한 지점에서만 중단됩니다.
  • delay, yield 같은 취소 가능한 함수를 호출해야 취소가 실제로 이루어집니다.

6.2 코루틴의 취소 상태 확인

코루틴 내에서 취소 상태를 확인하려면, isActive 속성을 사용합니다. isActive는 코루틴이 취소되었는지 여부를 확인할 수 있는 협력적 플래그입니다. 코루틴이 취소되면 isActivefalse가 됩니다.

isActive를 사용한 취소 상태 확인 예제

import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch {
        repeat(1000) { i ->
            if (!isActive) return@launch  // 취소 상태 확인
            println("Job: I'm working on $i ...")
            delay(500L)
        }
    }

    delay(1300L)
    println("Main: I'm tired of waiting!")
    job.cancel()
    println("Main: Now I can quit.")
}

설명:

  • isActive는 코루틴의 취소 상태를 확인하는 데 사용됩니다.
  • 코루틴이 취소되면 isActivefalse가 되어, 더 이상 작업을 진행하지 않고 즉시 중단됩니다.

출력:

Job: I'm working on 0 ...
Job: I'm working on 1 ...
Job: I'm working on 2 ...
Main: I'm tired of waiting!
Main: Now I can quit.

요점:

  • isActive는 코루틴이 취소되었는지 여부를 확인하는데 사용되며, 이를 통해 중단 가능한 작업을 제어할 수 있습니다.

6.3 코루틴의 정리 작업 (Clean-up)

코루틴이 취소될 때, 특정한 정리 작업을 수행해야 할 때가 있습니다. 이를 위해 try-finally 블록을 사용할 수 있습니다. finally 블록은 코루틴이 취소되더라도 항상 실행됩니다.

코루틴 취소 시 정리 작업 예제

import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch {
        try {
            repeat(1000) { i ->
                println("Job: I'm working on $i ...")
                delay(500L)
            }
        } finally {
            println("Job: I'm running finally block to clean up resources.")
        }
    }

    delay(1300L)
    println("Main: I'm tired of waiting!")
    job.cancelAndJoin()  // 코루틴을 취소하고 종료될 때까지 기다림
    println("Main: Now I can quit.")
}

설명:

  • try-finally를 사용하여 취소된 후에도 정리 작업을 수행할 수 있습니다.
  • finally 블록은 코루틴이 취소되더라도 항상 실행되므로, 리소스를 정리하거나 파일을 닫는 작업을 처리하는 데 유용합니다.

출력:

Job: I'm working on 0 ...
Job: I'm working on 1 ...
Job: I'm working on 2 ...
Main: I'm tired of waiting!
Job: I'm running finally block to clean up resources.
Main: Now I can quit.

요점:

  • try-finally를 통해 취소된 후에도 정리 작업을 안전하게 처리할 수 있습니다.
  • cancelAndJoin()은 코루틴을 취소하고, 완전히 종료될 때까지 기다립니다.

6.4 코루틴 타임아웃 (Timeout)

때로는 코루틴이 특정 시간 내에 완료되지 않으면 자동으로 취소되어야 하는 상황이 있습니다. 이를 위해 withTimeout 함수를 사용할 수 있습니다. withTimeout은 주어진 시간이 지나면 TimeoutCancellationException을 던지며, 코루틴을 취소합니다.

withTimeout 사용 예제

import kotlinx.coroutines.*

fun main() = runBlocking {
    try {
        withTimeout(1300L) {  // 1.3초 후에 타임아웃 발생
            repeat(1000) { i ->
                println("I'm working on $i ...")
                delay(500L)  // 0.5초 지연
            }
        }
    } catch (e: TimeoutCancellationException) {
        println("Timed out!")
    }
}

설명:

  • withTimeout을 사용하면 지정한 시간이 지나면 코루틴이 취소됩니다.
  • 타임아웃이 발생하면 TimeoutCancellationException이 발생하며, 이를 try-catch로 처리할 수 있습니다.

출력:

I'm working on 0 ...
I'm working on 1 ...
I'm working on 2 ...
Timed out!

요점:

  • withTimeout을 통해 지정된 시간 내에 완료되지 않는 작업자동으로 취소할 수 있습니다.
  • 타임아웃 발생 시 TimeoutCancellationException을 처리하여 정리 작업을 수행하거나 오류를 처리할 수 있습니다.

6.5 withTimeoutOrNull: 타임아웃 시 null 반환

때로는 타임아웃이 발생해도 예외를 발생시키지 않고, 대신 null을 반환하게 하고 싶을 수 있습니다. 이럴 때는 withTimeoutOrNull을 사용하면 됩니다.

withTimeoutOrNull 사용 예제

import kotlinx.coroutines.*

fun main() = runBlocking {
    val result = withTimeoutOrNull(1300L) {  // 1.3초 후에 타임아웃 발생
        repeat(1000) { i ->
            println("I'm working on $i ...")
            delay(500L)  // 0.5초 지연
        }
        "Completed"  // 작업이 완료되면 이 값을 반환
    }

    if (result == null) {
        println("Timed out!")
    } else {
        println("Result: $result")
    }
}

설명:

  • withTimeoutOrNull은 타임아웃이 발생하면 null을 반환하고, 작업이 정상적으로 완료되면 결과 값을 반환합니다.
  • 이를 통해 타임아웃이 발생했는지 여부를 쉽게 확인할 수 있습니다.

출력:

I'm working on 0 ...
I'm working on 1

 ...
I'm working on 2 ...
Timed out!

요점:

  • withTimeoutOrNull타임아웃 시 예외를 발생시키지 않고, null을 반환하여 더 유연하게 처리할 수 있습니다.

요약

  1. 코루틴 취소협력적으로 이루어지며, 취소 상태를 확인하는 isActive 또는 취소 가능한 함수(delay, yield)를 통해 이루어집니다.
  2. try-finally를 통해 코루틴 취소 시에도 정리 작업을 수행할 수 있습니다.
  3. 타임아웃withTimeout을 사용하여 특정 시간 내에 완료되지 않는 작업을 자동으로 취소할 수 있습니다.
  4. withTimeoutOrNull은 타임아웃 시 null을 반환하여 유연하게 타임아웃을 처리할 수 있습니다.
728x90
댓글