如何编写 Kotlin 口语代码同步重试直到超时或成功?

Posted

技术标签:

【中文标题】如何编写 Kotlin 口语代码同步重试直到超时或成功?【英文标题】:How to write Kotlin-colloquial code to retry synchronously until timeout or success? 【发布时间】:2019-11-17 03:39:12 【问题描述】:

阅读 Kotlin 文档后,我想出了以下代码(它不起作用 - 见下文)重复函数调用,直到它返回 true 或达到超时。 我想暂停执行,直到此代码块超时或成功 - 它不应该异步执行。

Log.d(TAG, "This is the last line to be logged")
runBlocking 
    Log.d(TAG, "this line is never logged")
    try 
        withTimeout(timeoutMsL) 
            while ((isActive) && (!success)) 
                success = doSomething()
            
         
    
    catch (ex: TimeoutCancellationException) 
        Log.d(TAG, "this line is never logged either")
        doSomethingElse()
    

timeoutMsLLong,典型值为 50 毫秒。 此代码通过 JNI 从 C++ 调用。当我运行它时

runBlocking 块内没有任何内容运行 runBlocking 块运行后什么都没有 控制权返回给 C++ 调用者 JNI 中存在异常,但 JNI 不记录 Kotlin 或 Java 异常详细信息。 adb 中没有记录异常 当我尝试使用 try/catch/log 块包围上述代码 sn-p 以捕获 Kotlin 异常时,没有记录任何内容

我已经读到应该避免使用runBlocking,但你也必须从现有的协程中调用withTimeout。 如果我使用正常的协程,调用函数的执行将在达到超时/成功之前继续 - 我需要防止这种情况发生。

在 Kotlin 中应该如何编码?

【问题讨论】:

【参考方案1】:

您的问题可能在于doSomething()。 Kotlin 的协程实现在很大程度上依赖于协作执行,其中子协程检查标志以查看它们是否已被取消(就像 withTimeout() 会做的那样)。这意味着外部协程将暂停,直到它们确认子协程已经结束,从而阻塞整个函数。

如果doSomething 永远不会挂起并且永远不会检查它是否仍然处于活动状态,那么无论外部情况如何,它都会一直运行直到完成。

要解决此问题,有两种选择:

    doSomething() 设为suspend 函数并定期使用yield()ensureActive() 暂停以响应取消。 在旨在中断正常阻塞代码(如withContext(Dispatchers.IO))的调度程序上执行它。

【讨论】:

我以为我用这行代码覆盖了这种可能性:while ((isActive) && (!success)) .它检查 withTimeout 协程中的 IsActive 参数。 它需要doSomething() 在该代码运行之前返回,如果它永远不会返回该代码永远不会运行。 doSomething 是一个简短的函数。它应该返回。我在此代码之前添加了一个带有单个日志记录行的小型 runBlocking 块,并且此行也从未记录过。出于某种原因,我的代码每次遇到 runBlocking 时都会退出。我不明白发生了什么。 感谢您的回复。隐含地,您已经确认我的代码是正确的。该代码位于 AAR 中,该 AAR 是 Xamarin android 绑定库的一部分。我现在已经证明 Xamarin 不能识别 Kotlin 协程。我找不到任何支持它们的 Xamarin 库(相当于 Xamarin 的 org.jetbrains.kotlinx:kotlinx-coroutines-core:1.0.1) 最后一个问题——如何在不使用协同程序的情况下在 Kotlin 中实现相同的功能?我只想继续从缓冲区(锁内)读取数据,并在获得给定字节数时退出,否则在超时时退出。

以上是关于如何编写 Kotlin 口语代码同步重试直到超时或成功?的主要内容,如果未能解决你的问题,请参考以下文章

java客户端调用webservice时 连接超时知道是网络原因 ,如何重试如果不重试程序就死琐了,

测试总结--同步或异步处理过程中常见的问题

使用 Serverless Aurora 时 Sequelize 连接超时,寻找增加超时持续时间或重试连接的方法

jedis超时重试机制注意事项

RxSwift - 使用 maxCount 重试网络请求直到成功

python2中MySQLdb加入超时及其重试功能