Estoy tratando de crear algunas rutinas (async) en un bucle. Quiero comenzar todo en paralelo y luego esperar a que todos terminen antes de continuar. La documentación proporciona el siguiente ejemplo:
coroutineScope { val deferreds = listOf( // fetch two docs at the same time async { fetchDoc(1) }, // async returns a result for the first doc async { fetchDoc(2) } // async returns a result for the second doc deferreds.awaitAll() // use awaitAll to wait for both network requests } pero esto requiere que todas las instanciaciones de clase se conozcan de antemano. Sin embargo, con un número variable de instanciaciones esto no es práctico. Como solución alternativa, descubrí que lo siguiente funciona: dada una Lista mutable de objetos de clase de la clase MyObject y MyObject tiene un método llamado myDo()
private val mObjects = mutableListOf<MyObject>()e ignorando la verificación de errores y asumiendo que la lista tiene 2 o más objetos, entonces lo siguiente funciona pero es un poco torpe y no muy elegante
coroutineScope { val pd = async { myObjects[0].myDo() } val dds = mutableListOf(pd) for (i in 1..numObjects - 1) { dds.add(async {mObjects[i].myDo() }) } val nds = dds.toList() nds.awaitAll() }// end coroutineScopeLo que esperaba hacer era algo como
val dds = mutableListOf<Job>() for (i in 0..numObjects - 1) { dds.add(async {mObjects[i].myDo() }) } val nds = dds.toList() nds.awaitAll()pero esto no funciona ya que el resultado asíncrono es un
Deferred<out T> : Jobinterfaz no una interfaz de trabajo. El problema con esto está en la línea.
val dds = mutableListOf<Job>()No sé qué usar en lugar de Job. Es decir, para asíncrono, ¿qué es T?
Cualquier ayuda o sugerencias serán apreciadas
T en este caso es cualquier tipo que myDo() .
Creo que lo está complicando demasiado al crear MutableLists adicionales. Puedes hacerlo así:
val results = coroutineScope { mObjects.map { obj -> async { obj.myDo() } }.awaitAll() } los results serán List<MyDoReturnType> .
Editar: Me acabo de dar cuenta, ya que no era obvio para usted que el tipo de Diferido es lo que devuelve la lambda async , tal vez sea porque myDo() no devuelve nada (implícitamente devuelve la Unidad). Si ese es el caso, debe usar launch en lugar de async . La única diferencia entre ellos es que la lambda de async devuelve algo y la de launch no. Deferred hereda de Job porque Deferred es un Job con un resultado. Si myDo() no devuelve nada, su código debería verse como el siguiente, sin ningún resultado.
coroutineScope { for (obj in mObjects) launch { obj.myDo() } }La respuesta de TenFour04 proporcionó la clave de mi respuesta. El siguiente código funciona para mí.
coroutineScope { val dds = mutableListOf<Deferred<Unit>>() for (item in mObjects) { dds.add(async {item.myDo() }) } val nds = dds.toList() nds.awaitAll() }¡¡¡Soy estúpido!!! o que. Después de que lo descubrí, la respuesta es casi trivial. La mejor solución que encontré es
private val mObjects = mutableListOf<MyObject>() coroutineScope {val deferreds = listOf(mObjects.size){async{mObjects[it].myDo()}} deferreds.awaitAll() }// end coroutineScopeMe gusta más esto que la solución de mapas, ya que no crea un conjunto de pares intermedio