Entonces, mirando Coroutines por primera vez, quiero procesar una carga de datos en paralelo y esperar a que termine. Estuve mirando alrededor y vi RunBlocking y Await, etc., pero no estoy seguro de cómo usarlo.
tengo hasta ahora
val jobs = mutableListOf<Job>() jobs += GlobalScope.launch { processPages(urls, collection) } jobs += GlobalScope.launch { processPages(urls, collection2) } jobs += GlobalScope.launch { processPages(urls, collection3) }Entonces quiero saber/esperar a que terminen
No necesita realizar un seguimiento manual de sus trabajos actuales si utiliza el concepto de simultaneidad estructurada. Suponiendo que su función processPages realiza algún tipo de bloqueo de IO, puede encapsular su código en la siguiente función de suspensión, que ejecuta su código en un despachador de IO diseñado para este tipo de trabajo:
suspend fun processAllPages() = withContext(Dispatchers.IO) { // withContext waits for all children coroutines launch { processPages(urls, collection) } launch { processPages(urls, collection2) } launch { processPages(urls, collection3) } } Ahora, si una función superior de su aplicación aún no es una función de suspensión, puede usar runBlocking para llamar a processAllPages :
runBlocking { processAllPages() }Puede usar la función de generador async para procesar una carga de datos en paralelo:
class Presenter { private var job: Job = Job() private var scope = CoroutineScope(Dispatchers.Main + job) // creating the scope to run the coroutine. It consists of Dispatchers.Main (coroutine will run in the Main context) and job to handle the cancellation of the coroutine. fun runInParallel() { scope.launch { // launch a coroutine // runs in parallel val deferredList = listOf( scope.asyncIO { processPages(urls, collection) }, scope.asyncIO { processPages(urls, collection2) }, scope.asyncIO { processPages(urls, collection3) } ) deferredList.awaitAll() // wait for all data to be processed without blocking the UI thread // do some stuff after data has been processed, for example update UI } } private fun processPages(...) {...} fun cancel() { job.cancel() // invoke it to cancel the job when you don't need it to execute. For example when UI changed and you don't need to process data } } Función de extensión asyncIO :
fun <T> CoroutineScope.asyncIO(ioFun: () -> T) = async(Dispatchers.IO) { ioFun() } // CoroutineDispatcher - runs and schedules coroutines No se recomienda el uso de GlobalScope.launch a menos que desee que la rutina funcione durante toda la vida útil de la aplicación y no se cancele prematuramente.
Editar: como lo mencionó Roman Elizarov, puede intentar no usar la función awaitAll() a menos que desee actualizar la interfaz de usuario o hacer otra cosa de inmediato después de que se procesen todos los datos.
Se puede utilizar el siguiente enfoque.
fun myTask() { GlobalScope.launch { val task = listOf( async { }, async { } ) task.awaitAll() } }