Kotlin Coroutines: ожидание завершения нескольких потоков - PullRequest
0 голосов
/ 24 февраля 2019

Итак, глядя на Coroutines в первый раз, я хочу обработать загрузку данных параллельно и дождаться ее завершения.Я оглядывался по сторонам и видел RunBlocking, Await и т. Д., Но не уверен, как его использовать.

У меня пока есть

val jobs = mutableListOf<Job>()
jobs += GlobalScope.launch { processPages(urls, collection) }
jobs += GlobalScope.launch { processPages(urls, collection2) }
jobs += GlobalScope.launch { processPages(urls, collection3) }

. Затем я хочу знать / ждать, пока они закончат

Ответы [ 2 ]

0 голосов
/ 24 февраля 2019

Вам не нужно вручную отслеживать ваши текущие задания, если вы используете концепцию структурированного параллелизма.Предполагая, что ваша функция processPages выполняет своего рода блокировку ввода-вывода, вы можете инкапсулировать свой код в следующую функцию приостановки, которая выполняет ваш код в диспетчере ввода-вывода, предназначенном для такой работы:

suspend fun processAllPages() = withContext(Dispatchers.IO) { 
    // withContext waits for all children coroutines 
    launch { processPages(urls, collection) }
    launch { processPages(urls, collection2) }
    launch { processPages(urls, collection3) }
}

Сейчасесли верхняя функция вашего приложения уже не является приостановленной, вы можете использовать runBlocking для вызова processAllPages:

runBlocking {
    processAllPages()
}
0 голосов
/ 24 февраля 2019

Вы можете использовать функцию async builder для параллельной обработки загрузки данных:

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
    }
}

Функция расширения asyncIO:

fun <T> CoroutineScope.asyncIO(ioFun: () -> T) = async(Dispatchers.IO) { ioFun() } // CoroutineDispatcher - runs and schedules coroutines

GlobalScope.launch не рекомендуется использовать , если вы не хотите, чтобы сопрограмма работала на протяжении всего времени жизни приложения и не была отменена преждевременно.

Редактировать: как упоминал Роман Елизаров, вы можете попытаться не использовать функцию awaitAll(), если толькоВы хотите обновить пользовательский интерфейс или сделать что-то еще сразу после обработки всех данных.

...