Котлин: сфера действия сопрограмм против контекста сопрограмм

Кто-нибудь может объяснить разницу между ними? Я думаю, что видимость предоставляет ссылку (например, Job), чтобы отменить их, а контекст предоставляет ссылку на основной поток. Это так?

3 ответа

Да, в принципе вы правы, подробнее здесь.

Объем

  • сопрограмма должна работать в области видимости
  • это способ отслеживать все выполняющиеся в нем сопрограммы
  • все (кооперативные) сопрограммы могут быть отменены через их область видимости
  • области получают неперехваченные исключения
  • они являются способом привязки сопрограмм к конкретному жизненному циклу приложения (например, viewModelScope в Android), чтобы избежать утечки

Контекст

Контекст определяет, в каком потоке будут выполняться сопрограммы. Есть четыре варианта:

  • Dispatchers.Default - для интенсивной работы процессора (например, сортировка большого списка)
  • Dispatchers.Main - что это будет, зависит от того, что вы добавили в зависимости времени выполнения ваших программ (например, kotlinx-coroutines-android, для потока пользовательского интерфейса в Android)
  • Dispatchers.Unconfined - запускает неограниченные сопрограммы без определенного потока
  • Dispatchers.IO - для тяжелых операций ввода-вывода (например, длительные запросы к базе данных)

В следующем примере объединены область действия и контекст. Он создает новую область видимости, в которой сопрограммы будут выполняться (если не изменены) в потоке, предназначенном для работы ввода-вывода, и отменяет их через их область действия.

val scope = CoroutineScope(context = Dispatchers.IO) 
val job = scope.launch {
    val result = suspendFunc1()
    suspendFunc2(result)
}
// ...
scope.cancel() // suspendFunc1() and suspendFunc2() will be cancelled

Они действительно тесно связаны. Вы могли бы сказать, что CoroutineScope формализует способ CoroutineContext наследуется

CoroutineScope не имеет данных сам по себе, он просто содержит CoroutineContext, Его ключевая роль - неявный получатель блока, который вы передаете launch, async и т.п.

Смотрите этот пример:

runBlocking {
    val scope0 = this
    // scope0 is the top-level coroutine scope.
    scope0.launch {
        val scope1 = this
        // scope1 inherits its context from scope0. It replaces the Job field
        // with its own job, which is a child of the job in scope0.
        // It retains the Dispatcher field so the launched coroutine uses
        // the dispatcher created by runBlocking.
        scope1.launch {
            val scope2 = this
            // scope2 inherits from scope1
        }
    }
}

Вы можете увидеть, как CoroutineScope опосредует наследование сопрограммных контекстов. Если вы отмените работу в scope1, это будет распространяться на scope2 и отменит launchработа также.

Обратите внимание на ключевую синтаксическую особенность: я написал явно scope0.launch, но я только что написал launch, это будет означать точно то же самое. Вот как CoroutineScope помогает "автоматически" распространять сферу.

CoroutineScope имеет CoroutineContext,

Например, если у вас есть:

runBlocking { // defines coroutineScope

    launch(Dispatchers.Default) { //inherits coroutineScope but changes context

    }
}

runBlocking определяет CoroutineScope (узнать об этом здесь), который launch наследует. Контекст переопределяется путем явного указания диспетчера здесь. Если вы посмотрите на определение launchВы можете видеть, что это необязательно CoroutineContext:

public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    ...
)

Другой частью контекста будет имя сопрограммы:

launch(CoroutineName("launchMe") + Dispatchers.Default) {
    println("")
}

Объем

Каждый конструктор сопрограмм (например, запуск, асинхронность и т. Д.) И каждая функция определения объема (например, coroutineScope, withContext и т. Д.) Предоставляют свою собственную область с собственным экземпляром Job во внутренний блок кода, который она выполняет. По соглашению, они все ждут завершения всех сопрограмм внутри своего блока, прежде чем завершить себя, тем самым укрепляя дисциплину структурированного параллелизма.

Источник

контекст

Сопрограммы всегда выполняются в некотором контексте, который представлен значением типа CoroutineContext, определенного в стандартной библиотеке Kotlin.

Контекст сопрограммы представляет собой набор различных элементов. Основными элементами являются работа сопрограммы, которую мы видели ранее, и ее диспетчер, который рассматривается в этом разделе.

Источник

Другие вопросы по тегам