Каков эффект от использования coroutineScope в runBlocking? - PullRequest
1 голос
/ 16 мая 2019

в котлин сопрограмм док , это объясняет "разницу между runBlocking и coroutineScope":

Scope builder

В дополнение к области сопрограмм, предоставляемой различными компоновщиками, можно объявить собственную область с помощью компоновщика coroutineScope. Он создает область сопрограммы и не завершается, пока не завершатся все запущенные дочерние элементы. The main difference between runBlocking and coroutineScope is that the latter does not block the current thread while waiting for all children to complete.

Я не совсем понимаю, код примера показывает

import kotlinx.coroutines.*

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

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

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

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

журнал:

2019-05-16 10:47:45.107 12239-12239 +++ before enter runBlocking{}
2019-05-16 10:47:45.219 12239-12239 +++ Task from coroutine scope
2019-05-16 10:47:45.320 12239-12239 +++ Task from runBlocking
2019-05-16 10:47:45.620 12239-12239 +++ Task from nested launch
2019-05-16 10:47:45.621 12239-12239 +++ ---after exit runBlocking{}

и +++ Task from nested launch отображается после +++ Task from runBlocking, как и ожидалось, так как он имеет задержку 500L.

Но если добавить некоторые другие launch компоновщики после блока coroutineScop{}, результат будет сбивающим с толку.

Здесь добавляются два launch после coroutineScop{} с задержкой 30L и 100L.

Я ожидал, что журнал для задержки 30L должен появиться раньше, чем задержка 300L внутри coroutineScop{}, но он появляется после того, как все launch сделаны внутри coroutineScop{}

fun testCoroutines() {
Log.e("+++", "+++ enter testCoroutines_3")
runBlocking {
    launch {
        println("+++ start Task from runBlocking, with 200L delay")
        delay(200L)
        println("+++ end Task from runBlocking, with 200L delay")
    }

    launch {
        println("+++ start Task from runBlocking, with 50L delay")
        delay(50L)
        println("+++ end Task from runBlocking, with 50L delay")
    }

    launch {
        println("+++ start Task from runBlocking, with 70L delay")
        delay(70L)
        println("+++ end Task from runBlocking, with 70L delay")
    }

    coroutineScope {
        println("+++ enter Task from coroutineScope")
        // Creates a coroutine scope
        launch {
            Log.v("+++", "+++ === start Task from nested launch, 500L")
            delay(500L)
            Log.v("+++", "+++ --- end Task from nested launch, 500L")
        }

        delay(100L)
        println("+++ in Task from coroutineScope after delay(100L)")

        launch {
            Log.v("+++", "+++ === start Task from nested launch, 300L")
            delay(300L)
            Log.v("+++", "+++ --- end Task from nested launch, 300L")
        }

        println("+++ --- exit Task from coroutine scope") // This line will be printed before the nested launch
    }

    launch {
        println("+++ start Task from runBlocking, with 30L delay")
        delay(30L)
        println("+++ end Task from runBlocking, with 30L delay")
    }

    launch {
        println("+++ start Task from runBlocking, with 100L delay")
        delay(100L)
        println("+++ end Task from runBlocking, with 100L delay")
    }

}

Log.e("+++", "--- exit  testCoroutines_3 scope is over") // This line is not printed until the nested launch completes

}

журнал:

10:35:05.819 4657-4657 +++ enter testCoroutines_3
10:35:05.828 4657-4657 +++ enter Task from coroutineScope
10:35:05.833 4657-4657 +++ start Task from runBlocking, with 200L delay
10:35:05.833 4657-4657 +++ start Task from runBlocking, with 50L delay
10:35:05.833 4657-4657 +++ start Task from runBlocking, with 70L delay
10:35:05.834 4657-4657 +++ === start Task from nested launch, 500L
10:35:05.885 4657-4657 +++ end Task from runBlocking, with 50L delay
10:35:05.905 4657-4657 +++ end Task from runBlocking, with 70L delay
10:35:05.932 4657-4657 +++ in Task from coroutineScope after delay(100L)
10:35:05.933 4657-4657 +++ --- exit Task from coroutine scope
10:35:05.935 4657-4657 +++ === start Task from nested launch, 300L
10:35:06.034 4657-4657 +++ end Task from runBlocking, with 200L delay
10:35:06.235 4657-4657 +++ --- end Task from nested launch, 300L
10:35:06.334 4657-4657 +++ --- end Task from nested launch, 500L
10:35:06.335 4657-4657 +++ start Task from runBlocking, with 30L delay
10:35:06.335 4657-4657 +++ start Task from runBlocking, with 100L delay
10:35:06.366 4657-4657 +++ end Task from runBlocking, with 30L delay
10:35:06.436 4657-4657 +++ end Task from runBlocking, with 100L delay
10:35:06.437 4657-4657--- exit  testCoroutines_3 scope is over

думал, что по крайней мере +++ start Task from runBlocking, with 30L delay должен появиться раньше после +++ === start Task from nested launch, 500L и до +++ end Task from runBlocking, with 50L delay, но это не так и появляется после того, как все launch сделаны в +++ --- end Task from nested launch, 500L.

Что делает coroutineScope в блоке сопрограмм?

(я тестировал, используя приложение для Android с нажатием кнопки, чтобы вызвать testCoroutines)

Ответы [ 3 ]

2 голосов
/ 16 мая 2019

Тот факт, что coroutineScope не является блокирующим, не означает, что он не ожидает завершения своих дочерних сопрограмм.

На самом деле, и runBlocking, и coroutineScope будут ждать завершения каждого дочернего сопрограмма, прежде чем завершить.

Реальная разница между двумя - как они ждут. runBlocking блокирует текущий поток, в то время как coroutineScope приостанавливает текущую сопрограмму.

1 голос
/ 16 мая 2019

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

Будьте внимательны, чтобы отличить «не завершено до» от «заблокировать вызывающий поток до». runBlocking единственный, кто делает последнее.

0 голосов
/ 28 июня 2019

эта ссылка также помогает.

enter image description here

цитата: «Глядя на то, как выполняется fetchDocs, вы можете увидеть, как работает suspend. Каждый раз, когда сопрограмма приостанавливается, текущий кадр стека (место, которое Kotlin использует для отслеживания, какая функция выполняется и ее переменные) копируется и сохраняется для последующего использования. Когда это возобновляется, кадр стека копируется обратно с того места, где он был сохранен, и снова запускается. В середине анимации - когда все сопрограммы в основном потоке приостановлены, основной поток может обновиться бесплатно. экран и обрабатывать пользовательские события. Вместе приостановить и возобновить заменить обратные вызовы. "

...