Сопрограммы: runBlocking против coroutineScope - PullRequest
0 голосов
/ 29 ноября 2018

Я читал Основы Coroutine , пытаясь понять и выучить его.

Там есть часть с этим кодом:

fun main() = runBlocking { // this: CoroutineScope
    launch { 
        delay(200L)
        println("Task from runBlocking")
    }

    coroutineScope { // Creates a new coroutine scope
        launch {
            delay(900L) 
            println("Task from nested launch")
        }

        delay(100L)
        println("Task from coroutine scope") // This line will be printed before nested launch
    }

    println("Coroutine scope is over") // This line is not printed until nested launch completes
}

Вывод выглядит так:

Task from coroutine scope
Task from runBlocking
Task from nested launch
Coroutine scope is over

Мой вопрос: почему эта строка:

 println("Coroutine scope is over") // This line is not printed until nested launch completes

всегда вызывается последней?

Разве она не должна вызываться после:

coroutineScope { // Creates a new coroutine scope
    ....
}

приостановлено?

Там также есть примечание:

Основное различие между runBlocking и coroutineScope заключается в том, что последний не блокирует текущий поток во время ожиданиявсе дети, чтобы закончить.

Я не понимаю, как coroutineScope и RunBlocking здесь отличаются?coroutineScope выглядит как его блокировка, так как он достигает только последней строки, когда это сделано.

Может ли кто-нибудь просветить меня здесь?

Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 29 ноября 2018

Я не понимаю, чем отличаются coroutineScope и runBlocking?coroutineScope выглядит как его блокировка, поскольку он достигает последней строки только тогда, когда это сделано.

С точки зрения кода в блоке ваше понимание верно.Разница между runBlocking и coroutineScope происходит на более низком уровне: что происходит с потоком, пока сопрограмма заблокирована?

  • runBlocking не является suspend fun.Нить, вызвавшая его, остается внутри, пока сопрограмма не будет завершена.

  • coroutineScope - это suspend fun.Если ваша сопрограмма приостанавливается, функция coroutineScope также приостанавливается.Это позволяет функции верхнего уровня, не приостанавливающей функции , которая создала сопрограмму, продолжать выполнение в том же потоке.Поток "вышел" из блока coroutineScope и готов выполнить другую работу.

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


Хотя вышеизложенное описывает концептуальные сходства,он также должен показать вам, что runBlocking - это совершенно отличный инструмент от coroutineScope.

  • runBlocking - это низкоуровневая конструкция, предназначенная для использования только в коде фреймворка или автономных примерах, подобных вашему.Он превращает существующий поток в цикл событий и создает его сопрограмму с Dispatcher, которая отправляет возобновляемые сопрограммы в очередь цикла событий.

  • coroutineScope является конструкцией, ориентированной на пользователя,используется для определения границ задачи, которая распадается внутри нее параллельно.Вы используете его для удобного ожидания всей async работы, происходящей внутри него, получения окончательного результата и обработки всех сбоев в одном центральном месте.

0 голосов
/ 29 ноября 2018

runBlocking просто блокирует текущий поток, пока не будут завершены внутренние сопрограммы.Здесь поток, выполняющий runBlocking, будет заблокирован до тех пор, пока сопрограмма из coroutineScope не будет завершена.

Первый launch просто не позволит потоку выполнить инструкции, которые следуют послеrunBlocking, но позволит перейти к инструкциям, которые приходят сразу после этого блока launch - поэтому Task from coroutine scope печатается до Task from runBlocking.

Но вложено coroutineScope в контексте runBlocking не позволит потоку выполнять инструкции, которые идут после этого блока coroutineScope, потому что runBlocking будет блокировать поток, пока сопрограмма из coroutineScope не будет полностью завершена.И именно поэтому Coroutine scope is over всегда будет идти после Task from nested launch.

...