You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否为协程设置超时挂起?需求类似suspendCoroutine的超时函数

实现带超时的suspendCoroutine替代函数

当然可以实现这个需求!Kotlin协程框架其实已经给我们提供了现成的超时处理工具,我们只需要把它和suspendCoroutine结合起来,就能得到你想要的功能。

核心思路

核心逻辑就是用withTimeout(或withTimeoutOrNull)包裹suspendCoroutine调用——withTimeout会在指定时间内未完成时自动抛出超时异常,完美匹配你需要的"超时后抛出异常并继续执行"的需求。

具体实现代码

import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.withTimeout
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine
import java.util.concurrent.TimeoutException

/**
 * 带超时的suspendCoroutine替代函数
 * @param timeoutMillis 超时时间,单位毫秒
 * @param block 回调逻辑块,用法与原生suspendCoroutine完全一致
 * @throws TimeoutException 当回调未在超时时间内触发时抛出
 */
suspend fun <T> suspendCoroutineWithTimeout(
    timeoutMillis: Long,
    block: (kotlin.coroutines.Continuation<T>) -> Unit
): T {
    return try {
        withTimeout(timeoutMillis) {
            suspendCoroutine(block)
        }
    } catch (e: TimeoutCancellationException) {
        // 将协程自带的取消异常转换为标准TimeoutException
        throw TimeoutException("Coroutine timed out after $timeoutMillis ms")
    }
}

代码说明

  • withTimeout会创建一个限时作用域,若内部的suspendCoroutine未通过resume/resumeWithException完成,就会抛出TimeoutCancellationException
  • 我们捕获这个协程取消异常,转换为你需要的标准TimeoutException(如果不需要转换,直接抛出原异常也可,它本身是TimeoutException的子类)
  • 传入的block和原生suspendCoroutine用法完全一致,你可以像之前一样在回调里调用continuation.resume()或continuation.resumeWithException()

使用示例

模拟一个回调风格的异步API,测试超时场景:

// 模拟回调式异步函数
fun fetchRemoteData(callback: (Result<String>) -> Unit) {
    // 模拟2秒的耗时操作
    Thread.sleep(2000)
    callback(Result.success("Loaded remote data successfully"))
}

// 测试带超时的协程函数
suspend fun main() {
    try {
        // 设置1.5秒超时,此时fetchRemoteData会超时
        val data = suspendCoroutineWithTimeout(1500) { continuation ->
            fetchRemoteData { result ->
                result.fold(
                    onSuccess = { continuation.resume(it) },
                    onFailure = { continuation.resumeWithException(it) }
                )
            }
        }
        println(data)
    } catch (e: TimeoutException) {
        println("Request failed: ${e.message}")
    }
}

运行这段代码会触发超时,控制台打印Request failed: Coroutine timed out after 1500 ms。

可选:超时返回null而非抛出异常

如果你希望超时后不抛出异常,而是返回null,可以用withTimeoutOrNull实现:

suspend fun <T> suspendCoroutineWithTimeoutOrNull(
    timeoutMillis: Long,
    block: (kotlin.coroutines.Continuation<T>) -> Unit
): T? {
    return withTimeoutOrNull(timeoutMillis) {
        suspendCoroutine(block)
    }
}

这个版本在超时后返回null,你可以根据业务逻辑自行处理返回值,无需捕获异常。

注意事项

如果你的回调逻辑可能在超时后继续执行,建议添加一个标记判断协程是否已取消,避免重复调用resume导致异常。

内容的提问来源于stack exchange,提问作者usbpc102

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 10:07:51