概要
コルーチンを使うと、非同期処理を簡潔に書けるようになりますが、
「処理が終わらない」「通信が詰まる」 といったケースでは、
明示的にタイムアウト(Timeout) を設定して自動キャンセルすることが重要です。
Kotlinではこれを withTimeout() / withTimeoutOrNull() で実現します。
タイムアウトとは?
「一定時間内に完了しなければ、その処理をキャンセルする」仕組みです。
ネットワーク通信や重い計算など、いつ終わるかわからない処理でよく使われます。
基本構文
withTimeout(timeMillis: Long)
指定した時間を超えると 例外(TimeoutCancellationException) をスローします。
import kotlinx.coroutines.*
fun main() = runBlocking {
try {
withTimeout(1300L) { // ← 1.3秒でタイムアウト
repeat(1000) { i ->
println("I'm working $i ...")
delay(500L)
}
}
} catch (e: TimeoutCancellationException) {
println("Timeout! (${e.message})")
}
}
実行結果:
I'm working 0 ...
I'm working 1 ...
I'm working 2 ...
Timeout! (Timed out waiting for 1300 ms)
ポイント:
- タイムアウト発生時、ブロック内の処理はキャンセルされます。
- 内部的には「キャンセル(Cancellation)」機構が使われています。
- 親スコープにもキャンセルが伝播します。
withTimeoutOrNull を使う
例外を投げずに nullを返すだけで済ませたい場合はこちらが便利。
fun main() = runBlocking {
val result = withTimeoutOrNull(1300L) {
repeat(1000) { i ->
println("I'm working $i ...")
delay(500L)
}
"Done" // ← ここに到達しない
}
println("Result: $result")
}
出力:
I'm working 0 ...
I'm working 1 ...
I'm working 2 ...
Result: null
nullが返るので、try-catch不要。
例外制御を避けたい場合におすすめです。
内部動作:キャンセルとの関係
Kotlinの withTimeout() は内部的に次のように動きます:
つまり、タイムアウト = キャンセルの一種 です。
コルーチンがキャンセルに対応していれば、自動的に中断されます。
ネットワーク通信の例(Retrofit × Coroutines)
suspend fun fetchUserData(api: ApiService): User? {
return withTimeoutOrNull(5_000L) { // 5秒でタイムアウト
api.getUserInfo() // suspend関数
}
}
通信が5秒を超えると自動的にキャンセルされ、nullが返ります。
これにより無限待ちのリスクを防げます。
タイムアウトを活用する場面
| 使用場面 | 説明 |
|---|---|
| ネットワーク通信 | APIの応答が遅い場合に自動中断 |
| DBアクセス | クエリが長引く場合の制御 |
| 重い計算処理 | 無限ループ防止 |
| 外部I/O処理 | ファイル・ソケット操作の安全制御 |
タイムアウトとキャンセルの組み合わせ
複数ジョブを並列実行して、その中の一部だけにタイムアウトを設定することも可能です。
val job = launch {
withTimeout(2000L) {
repeat(100) { i ->
println("Task $i running ...")
delay(500L)
}
}
}
上記では job 自体の寿命は長くても、内部処理だけがタイムアウトします。
よくある落とし穴
| 問題 | 原因 | 対処 |
|---|---|---|
| タイムアウトが効かない | 処理がキャンセル非対応(isActiveを見ていない) |
明示的にisActiveやyield()を入れる |
| 例外でアプリが落ちる |
withTimeout使用時にtry-catch未対応 |
withTimeoutOrNullを使う |
| 親スコープまで止まる | Structured Concurrencyで伝播 |
supervisorScopeで隔離可能 |
まとめ
| メソッド | 動作 | 例外 | 返り値 |
|---|---|---|---|
withTimeout() |
タイムアウト時にキャンセル | TimeoutCancellationException |
なし |
withTimeoutOrNull() |
タイムアウト時にnullを返す | 発生しない | null |
KotlinのwithTimeoutは、
「協調的キャンセル」と「構造化並行性」の上に成り立つ強力な機能です。
アプリがハングするような不確実な処理に、
タイムアウトを明示的に設けることが信頼性向上の第一歩になります。