Spring REST 端点内的 Kotlin 协程
Kotlin coroutines within a Spring REST endpoint
给定一个 REST 端点和两个异步协程,每个 return 一个整数,我希望这个端点 return 它们的总和。这两个函数(funA 和 funB)应该 运行 并行,这样整个计算应该需要大约 3 秒。
我正在使用 SpringBoot 2.6.3 和 Kotlin Coroutines 1.6.0。这是我的尝试:
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
@RestController
class Controllers {
@GetMapping(
value = ["/summing"]
)
fun summing(): String {
val finalResult = runBlocking {
val result = async { sum() }
println("Your result: ${result.await()}")
return@runBlocking result
}
println("Final Result: $finalResult")
return "$finalResult"
}
suspend fun funA(): Int {
delay(3000)
return 10
}
suspend fun funB(): Int {
delay(2000)
return 90
}
fun sum() = runBlocking {
val resultSum = async { funA().await() + funB().await() }
return@runBlocking resultSum
}
}
问题是此代码无法编译,因为 await() 未被识别为有效方法。如果我删除 await() ,这两个函数将依次执行(总时间约为 5 秒),而不是预期结果 (100),我得到:
Your result: DeferredCoroutine{Completed}@1c1fe804
Final Result: DeferredCoroutine{Completed}@48a622de
因此端点 returns“DeferredCoroutine{Completed}@48a622de”。
我希望端点在 ~3 秒内变为 return“100”。我怎样才能做到这一点?
你真的把事情搞砸了 ;-) 你的代码有几个问题:
- 仅使用
runBlocking()
以在其中使用另一个 runBlocking()
。
- 使用
async()
并立即对其调用 await()
(在 summing()
中)- 它什么都不做。
funA().await()
和 funB().await()
真的没有任何意义。这些函数 return 整数,你不能 await()
已经获得的整数。
- 通常,使用的代码比需要的多。
解决方案非常简单:使用 runBlocking()
一次跳入协程世界,然后使用 async()
同时启动两个函数:
runBlocking {
val a = async { funA() }
val b = async { funB() }
a.await() + b.await()
}
或者:
runBlocking {
listOf(
async { funA() },
async { funB() },
).awaitAll().sum()
}
或者(短一点,但我认为这不太可读):
runBlocking {
val a = async { funA() }
funB() + a.await()
}
此外,runBlocking()
也不理想。我相信 Spring 支持协同程序,所以最好使 summing()
函数 suspend
并使用 coroutineScope()
而不是 runBlocking()
- 这样代码就赢了'不阻止任何线程。
给定一个 REST 端点和两个异步协程,每个 return 一个整数,我希望这个端点 return 它们的总和。这两个函数(funA 和 funB)应该 运行 并行,这样整个计算应该需要大约 3 秒。 我正在使用 SpringBoot 2.6.3 和 Kotlin Coroutines 1.6.0。这是我的尝试:
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
@RestController
class Controllers {
@GetMapping(
value = ["/summing"]
)
fun summing(): String {
val finalResult = runBlocking {
val result = async { sum() }
println("Your result: ${result.await()}")
return@runBlocking result
}
println("Final Result: $finalResult")
return "$finalResult"
}
suspend fun funA(): Int {
delay(3000)
return 10
}
suspend fun funB(): Int {
delay(2000)
return 90
}
fun sum() = runBlocking {
val resultSum = async { funA().await() + funB().await() }
return@runBlocking resultSum
}
}
问题是此代码无法编译,因为 await() 未被识别为有效方法。如果我删除 await() ,这两个函数将依次执行(总时间约为 5 秒),而不是预期结果 (100),我得到:
Your result: DeferredCoroutine{Completed}@1c1fe804
Final Result: DeferredCoroutine{Completed}@48a622de
因此端点 returns“DeferredCoroutine{Completed}@48a622de”。
我希望端点在 ~3 秒内变为 return“100”。我怎样才能做到这一点?
你真的把事情搞砸了 ;-) 你的代码有几个问题:
- 仅使用
runBlocking()
以在其中使用另一个runBlocking()
。 - 使用
async()
并立即对其调用await()
(在summing()
中)- 它什么都不做。 funA().await()
和funB().await()
真的没有任何意义。这些函数 return 整数,你不能await()
已经获得的整数。- 通常,使用的代码比需要的多。
解决方案非常简单:使用 runBlocking()
一次跳入协程世界,然后使用 async()
同时启动两个函数:
runBlocking {
val a = async { funA() }
val b = async { funB() }
a.await() + b.await()
}
或者:
runBlocking {
listOf(
async { funA() },
async { funB() },
).awaitAll().sum()
}
或者(短一点,但我认为这不太可读):
runBlocking {
val a = async { funA() }
funB() + a.await()
}
此外,runBlocking()
也不理想。我相信 Spring 支持协同程序,所以最好使 summing()
函数 suspend
并使用 coroutineScope()
而不是 runBlocking()
- 这样代码就赢了'不阻止任何线程。