Dado un punto final REST y dos rutinas asincrónicas, cada una de las cuales devuelve un número entero, quiero que este punto final devuelva su suma. Las dos funciones (funA y funB) deben ejecutarse en paralelo, de tal manera que todo el cálculo deba tomar ~3 segundos. Estoy usando SpringBoot 2.6.3 y Kotlin Coroutines 1.6.0. Aquí está mi intento:
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 } }
El problema es que este código no se compila ya que await() no se reconoce como un método válido. Si elimino await(), las dos funciones se ejecutan en serie (tiempo total ~5 segundos) y en lugar del resultado esperado (100), obtengo:
Your result: DeferredCoroutine{Completed}@1c1fe804 Final Result: DeferredCoroutine{Completed}@48a622de
y entonces el punto final devuelve "DeferredCoroutine{Completed}@48a622de".
Quiero que el punto final devuelva "100" en su lugar y dentro de ~ 3 segundos. ¿Cómo puedo conseguir esto?
Realmente arruinaste esto ;-) Hay varios problemas con tu código:
runBlocking()
solo para usar otro runBlocking()
dentro de él.async()
e inmediatamente llame a await()
en él (en summing()
); no hace nada.funA().await()
y funB().await()
realmente no tienen ningún sentido. Estas funciones devuelven números enteros, no puede await()
en números enteros ya adquiridos. La solución es bastante simple: use runBlocking()
una vez para saltar al mundo coroutine y luego use async()
para iniciar ambas funciones simultáneamente:
runBlocking { val a = async { funA() } val b = async { funB() } a.await() + b.await() }
O alternativamente:
runBlocking { listOf( async { funA() }, async { funB() }, ).awaitAll().sum() }
O (un poco más corto, pero lo considero menos legible):
runBlocking { val a = async { funA() } funB() + a.await() }
Además, runBlocking()
no es ideal. Creo que Spring tiene soporte para rutinas, por lo que sería mejor hacer que la función summing( summing()
se suspend
y usar coroutineScope()
en lugar de runBlocking()
; de esta manera, el código no bloqueará ningún hilo.