在Kotlin中,是否有可能用非挂起版本代替挂起乐趣,而不破坏调用者?



我在Kotlin中学习并发,来自c#/JavaScript背景,我忍不住比较一些概念。

在c#和JavaScript中,技术上我们可以将async函数重写为做同样事情的常规非异步版本,使用Task.ContinueWithPromise.then等。

函数的调用者甚至不会注意到差异(我在一篇博客文章中提到了这一点)。

在Kotlin中可能有suspend函数(即,不改变调用代码)吗?我不这么认为,但我还是想问一下。

我能想到的最接近的东西是下面(Kotlin playground链接),我仍然需要调用.await():

import kotlinx.coroutines.*
suspend fun suspendableDelay(ms: Long): Long {
delay(ms);
return ms;
}
fun regularDelay(ms: Long): Deferred<Long> {
val d = CompletableDeferred<Long>()
GlobalScope.async { delay(ms); d.complete(ms) }
return d;
}
suspend fun test(ms: Long): Long {
delay(ms);
return ms;
}
fun main() {
val r1 = runBlocking { suspendableDelay(250) }
println("suspendableDelay ended: $r1");
val r2 = runBlocking { regularDelay(500).await() }
println("regularDelay ended: $r2");
}

https://pl.kotl.in/_AmzanwcB

如果您在JVM 8或更高版本上,您可以创建一个函数,该函数在异步作业中调用挂起函数并返回一个CompletableFuture,该函数可用于通过回调(thenApplyAsync())或同步(get())获得结果。

val scope = CoroutineScope(SupervisorJob())
suspend fun foo(): Int {
delay(500)
return Random.nextInt(10)
}
fun fooAsync(): CompletableFuture<Int> = scope.async { foo() }.asCompletableFuture()
fun main() {
fooAsync()
.thenApplyAsync { println(it) }
Thread.sleep(1000)
}

以上需要kotlinx-coroutines-jdk8库。

我不知道有什么解决方案可以跨多个平台运行。

这只能在你将挂起函数更改为非挂起阻塞函数时才能工作,例如

private fun method(){
GlobalScope.launch {
val value = getInt()
}
}
// Calling coroutine can be suspended and resumed when result is ready
private suspend fun getInt(): Int{
delay(2000)  // or some suspending IO call
return 5;
}
// Calling coroutine can't be suspended, it will have to wait (block)
private fun getInt(): Int{
Thread.sleep(2000)   // some blocking IO 
return 5;
}

在这里,您可以简单地使用非挂起版本,而不需要对调用者进行任何更改。

但是这里的问题是,如果没有suspend修饰符,函数就会阻塞,因此它不能导致coroutine挂起,基本上放弃了使用coroutiens的优势。

最新更新