Как планируются котлинские сопрограммы - PullRequest
0 голосов
/ 23 февраля 2019

В последнее время я читал много статей и смотрел много видео о совместных действиях Kotlin, и, несмотря на все мои усилия, я все еще не могу понять их в своей голове.

IКажется, я наконец нашел способ проиллюстрировать свою проблему:

class MyViewModel() : CoroutineScope {

override val coroutineContext = Dispatchers.Main + Job()

    fun foo() = launch(handler) {
        Log.e("test", "A")
    }
}

class MainActivity : Activity() {
    override fun onCreate() {
        MainViewModel().foo()
        Log.e("test", "B")
    }
}

Вывод этого:

E/test: B
E/test: A

И я не понимаю, как это может быть,Я использую только один поток (основной поток).Если мой код выполняется последовательно, к тому времени, как я достигну строки, log(B) ... log(A) уже должно быть напечатано.

Использует ли библиотека сопрограмм внутренние потоки для достижения этой цели?Это единственное объяснение, которое я мог придумать, но не нашел ничего такого в документах.

PS: Извините, что бросил android в микс, но этот код:

fun main() {
    GlobalScope.launch(Dispatchers.Unconfined) { // launch new coroutine in background and continue
        print(Thread.currentThread().name + "World!") // print after delay
    }
    (0 .. 1000).forEach { print(".") }
}

, кажется, работает как ожидалось и печатает: main @coroutine#1World!...........................

, потому что 1 thread == sequential work

Надеюсь, мой вопрос имеет смысл, спасибо за чтение!

1 Ответ

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

Под капотом Главный диспетчер использует Обработчик для публикации Runnable в MessageQueue.По сути, он будет добавлен в конец очереди событий.Это означает, что он будет выполнен в ближайшее время, но не сразу.Следовательно, почему «B» печатается перед «A».

Вы можете найти больше информации в этой статье .

РЕДАКТИРОВАТЬ OP (см. Статью вышеперед прочтением):

Просто хотел уточнить, почему вышеприведенный пример Android работает нормально, если кому-то все еще интересно.

fun main() {
    GlobalScope.launch(Dispatchers.Unconfined) { // launch new coroutine in background and continue
        print(Thread.currentThread().name + "World!") // print after delay
    }
    (0 .. 1000).forEach { print(".") }
}

Мы настраиваем GlobalScopeиспользовать диспетчер UNCONFINED, и для этого диспетчера isDispatchNeeded установлено на false.false означает «расписание в текущем потоке», и поэтому мы видим, что журналы печатаются последовательно.UNCONFINED не следует использовать в обычном коде.

Для всех других диспетчеров isDispatchNeeded установлено true, даже для диспетчера пользовательского интерфейса.см .: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/is-dispatch-needed.html

(кстати, GlobalScope использует диспетчер Default, если мы его не указываем)

...