我在Kotlin中学习并发,来自c#/JavaScript背景,我忍不住比较一些概念。
在c#和JavaScript中,技术上我们可以将async
函数重写为做同样事情的常规非异步版本,使用Task.ContinueWith
或Promise.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的优势。