非阻塞协程示例
Non-blocking coroutine example
我刚刚开始学习协程并设法编写了一个简单的阻塞协程,旨在重试远程休息服务的处理。 returns 如果他目前无法处理 foo 更新,那我就是个骗子。但我们有一个协议,我将尝试在接下来的 10 秒内更新 foo,间隔为 1 秒:
private fun updateFoo(fooId: String): Foo {
val updatedFoo = runBlocking {
return@runBlocking withTimeoutOrNull(10L) {
var result: Foo?
do {
result = try {
fooClient.update(fooId)
} catch (ex: Exception) {
null
}
if (result != null) {
return@withTimeoutOrNull result
}
delay(1L)
} while (result == null)
return@withTimeoutOrNull result
}
}
return updatedFoo ?: throw IllegalStateException(
"Could not update Foo ($fooId) with retries.")
}
关键是我运行协程阻塞了。十秒是一个足够大的间隔,所以我想将此方法重构为 运行 coroutine nonBlcking。
我尝试使用 launch { ... } 而不是 运行Blocking,但我得到了 Job,但我想那不是我想要的。谁能帮我写对吗???
假设 fooClient.update
已经是一个挂起函数,那么你的问题似乎真的是关于如何桥接 updateFoo
所在的非协程世界(因为它是一个非挂起函数) 与 fooClient.update
.
的协程世界
如果对问题的解释是正确的,那么您将需要使用传统机制从 updateFoo
获取异步结果,例如延迟结果或回调。
如果您的 updateFoo
代码 运行 在 async
块中,您可以 return Deferred<Foo?>
值例如:
fun updateFoo(fooId: String): Deferred<Foo?> {
return GlobalScope.async {
return@async withTimeoutOrNull(10L) {
var result: Foo?
do {
result = try {
update(fooId)
} catch (ex: Exception) {
null
}
if (result != null) {
return@withTimeoutOrNull result
}
delay(1L)
} while (result == null)
return@withTimeoutOrNull result
}
}
}
然后你可以在你的非协程代码中将其转换为 CompletableFuture
例如
asCompletableFuture()
注意:为了简单起见,我在这里使用了 GlobalScope
,但根据您的应用程序的要求,使用显式范围通常是个好主意。
你评论说fooClient.update
实际上是一个非挂起的阻塞函数。鉴于此,您应该 运行 它在专门为阻止此类调用而配置的适当线程池中,例如 Dispatchers.IO
:
withContext(Dispatchers.IO) {
update(fooId)
}
当 运行 像这样时,协程将不会阻塞 -- withContext
调用挂起。
我刚刚开始学习协程并设法编写了一个简单的阻塞协程,旨在重试远程休息服务的处理。 returns 如果他目前无法处理 foo 更新,那我就是个骗子。但我们有一个协议,我将尝试在接下来的 10 秒内更新 foo,间隔为 1 秒:
private fun updateFoo(fooId: String): Foo {
val updatedFoo = runBlocking {
return@runBlocking withTimeoutOrNull(10L) {
var result: Foo?
do {
result = try {
fooClient.update(fooId)
} catch (ex: Exception) {
null
}
if (result != null) {
return@withTimeoutOrNull result
}
delay(1L)
} while (result == null)
return@withTimeoutOrNull result
}
}
return updatedFoo ?: throw IllegalStateException(
"Could not update Foo ($fooId) with retries.")
}
关键是我运行协程阻塞了。十秒是一个足够大的间隔,所以我想将此方法重构为 运行 coroutine nonBlcking。
我尝试使用 launch { ... } 而不是 运行Blocking,但我得到了 Job,但我想那不是我想要的。谁能帮我写对吗???
假设 fooClient.update
已经是一个挂起函数,那么你的问题似乎真的是关于如何桥接 updateFoo
所在的非协程世界(因为它是一个非挂起函数) 与 fooClient.update
.
如果对问题的解释是正确的,那么您将需要使用传统机制从 updateFoo
获取异步结果,例如延迟结果或回调。
如果您的 updateFoo
代码 运行 在 async
块中,您可以 return Deferred<Foo?>
值例如:
fun updateFoo(fooId: String): Deferred<Foo?> {
return GlobalScope.async {
return@async withTimeoutOrNull(10L) {
var result: Foo?
do {
result = try {
update(fooId)
} catch (ex: Exception) {
null
}
if (result != null) {
return@withTimeoutOrNull result
}
delay(1L)
} while (result == null)
return@withTimeoutOrNull result
}
}
}
然后你可以在你的非协程代码中将其转换为 CompletableFuture
例如
asCompletableFuture()
注意:为了简单起见,我在这里使用了 GlobalScope
,但根据您的应用程序的要求,使用显式范围通常是个好主意。
你评论说fooClient.update
实际上是一个非挂起的阻塞函数。鉴于此,您应该 运行 它在专门为阻止此类调用而配置的适当线程池中,例如 Dispatchers.IO
:
withContext(Dispatchers.IO) {
update(fooId)
}
当 运行 像这样时,协程将不会阻塞 -- withContext
调用挂起。