0Pricing
Kotlin Academy · 강의

withTimeout과 withTimeoutOrNull

타임아웃 래퍼로 실행 시간을 제한하고 TimeoutCancellationException을 처리해 보세요.

withTimeout과 withTimeoutOrNull은(는) CoddyKit의 무료 Kotlin Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Kotlin Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

시간 제한이 필요한 이유

네트워크 또는 입출력 작업에서 코루틴이 무기한 멈출 수 있습니다. withTimeout은 지정된 밀리초 안에 완료되지 않으면 블록을 취소합니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    try {
        withTimeout(200) {
            delay(1000)  // simulates slow network
            println("This never prints")
        }
    } catch (e: TimeoutCancellationException) {
        println("Timed out!")
    }
}

withTimeout 기초

withTimeout(millis) { ... }은 블록이 제한 시간을 초과하면 TimeoutCancellationException(CancellationException의 하위 클래스)을 던집니다.

import kotlinx.coroutines.*
suspend fun fetchData(): String {
    delay(100)
    return "data"
}
fun main() = runBlocking {
    val result = withTimeout(500) {
        fetchData()
    }
    println(result) // data
}

withTimeoutOrNull

withTimeoutOrNull은 시간 제한이 초과되었을 때 예외를 던지는 대신 null을 반환하므로, 시간 제한을 일반적인 흐름으로 처리하기 쉽습니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val result: String? = withTimeoutOrNull(200) {
        delay(1000)
        "done"
    }
    println(result ?: "Timeout — using default")
}

반환 값이 있는 시간 제한

두 함수 모두 성공하면 블록의 마지막 식 값을 반환합니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val response = withTimeoutOrNull(500) {
        delay(100)
        mapOf("status" to 200, "body" to "OK")
    }
    println(response?.get("status")) // 200
}

시간 제한 중첩

내부 시간 제한이 먼저 만료됩니다. 내부 시간 제한이 먼저 취소하지 못할 때만 외부 시간 제한이 실행되므로, 요청별 시간 제한과 전역 시간 제한을 나누어 설정할 때 유용합니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    withTimeoutOrNull(1000) {       // global
        withTimeoutOrNull(200) {    // per-call
            delay(300)
            println("inner done")  // won't print
        } ?: println("Inner timed out")
        delay(100)
        println("outer still running")
    }
}

TimeoutCancellationException

TimeoutCancellationException은 CancellationException이므로 코루틴 메커니즘에서 정상적인 취소로 처리되며 부모 범위로 전파되지 않습니다.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val job = launch {
        try {
            withTimeout(100) { delay(1000) }
        } catch (e: TimeoutCancellationException) {
            println("Caught in child: ${e.message}")
        }
    }
    job.join()
    println("Parent still running: ${isActive}")
}

시간 제한 시 리소스 정리

시간이 다 되었을 때도 리소스를 해제하려면 withTimeout 내부에서 finally를 사용하십시오.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val result = withTimeoutOrNull(150) {
        try {
            println("Opening resource")
            delay(300)
            "result"
        } finally {
            println("Closing resource") // always runs
        }
    }
    println("Result: $result")
}

재시도와 시간 제한

시간 제한을 재시도 로직과 결합할 수 있습니다. 시도마다 시간 제한을 적용하여 작업을 실행하고, 결과가 null이면 재시도하십시오.

import kotlinx.coroutines.*
suspend fun tryFetch(attempt: Int): String? = withTimeoutOrNull(200) {
    delay(if (attempt < 3) 300L else 100L) // fails first 2 attempts
    "success on attempt $attempt"
}
fun main() = runBlocking {
    var result: String? = null
    var attempt = 1
    while (result == null) {
        result = tryFetch(attempt++)
    }
    println(result)
}

ViewModel에서 withTimeout 사용

안드로이드 ViewModel에서는 viewModelScope.launch 안에서 저장소 호출을 withTimeoutOrNull로 감싸 느린 응답이 발생했을 때 오류 상태를 표시할 수 있습니다.

import kotlinx.coroutines.*
// Pseudocode pattern:
suspend fun loadUser(): String = withTimeoutOrNull(3000) {
    // repo.getUser()
    delay(100)
    "Alice"
} ?: "Timeout — using cached data"
fun main() = runBlocking { println(loadUser()) }

정확도 관련 주의 사항

withTimeout은 코루틴 디스패처에 의존합니다. TestCoroutineScheduler를 사용하는 테스트에서는 시간이 가상으로 처리되며 수동으로 진행할 수 있습니다.

import kotlinx.coroutines.*
// In unit tests with runTest:
// runTest {
//     withTimeout(1000) {
//         delay(999)  // virtual time — completes instantly
//         println("done")
//     }
// }
fun main() = runBlocking {
    println("Use runTest for virtual-time timeout testing")
}

두 함수 중 선택하기

시간 제한을 오류로 처리할 때는 withTimeout을 사용하십시오. 시간 제한이 예상된 결과일 때(예: 캐시 누락 또는 선택적 사전 가져오기)는 withTimeoutOrNull을 사용하십시오.

import kotlinx.coroutines.*
fun main() = runBlocking {
    // Mandatory: throw on timeout
    // withTimeout(500) { criticalOp() }

    // Optional: null on timeout
    val cached = withTimeoutOrNull(50) {
        delay(200); "fresh"
    } ?: "stale"
    println(cached)
}

빠른 확인

블록이 시간 제한을 초과하면 withTimeoutOrNull은 무엇을 반환하나요?

복습

withTimeout은 시간 제한이 초과되면 예외를 던지고, withTimeoutOrNull은 null을 반환합니다. 두 함수 모두 블록을 협력적으로 취소하고 finally 블록을 실행합니다. 리소스 정리에는 finally를 사용하고, 시간 제한이 예상된 결과일 때는 withTimeoutOrNull을 사용하십시오.

자주 묻는 질문

“withTimeout과 withTimeoutOrNull” 강의는 무료인가요?

네 — “withTimeout과 withTimeoutOrNull” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Kotlin Academy 강의 전체를 잠금 해제할 수 있습니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“withTimeout과 withTimeoutOrNull”에서 뭘 배우나요?

타임아웃 래퍼로 실행 시간을 제한하고 TimeoutCancellationException을 처리해 보세요. 브라우저에서 직접 실행하는 실습 코드로 Kotlin Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Kotlin Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Kotlin Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“withTimeout과 withTimeoutOrNull” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Kotlin Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Kotlin Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 협력적 취소: isActive와 ensureActive
  2. withTimeout과 withTimeoutOrNull
  3. finally와 NonCancellable로 정리하기
  4. 코루틴 계층 구조에서 취소 전파
← Kotlin Academy(으)로 돌아가기