Как Kotlin элементы сопрограммы доступны в текущем контексте? - PullRequest
1 голос
/ 16 марта 2020

Я пытаюсь узнать, как работают сопрограммы в Kotlin. Я прочитал несколько статей в Интернете, в том числе эту - https://proandroiddev.com/demystifying-coroutinecontext-1ce5b68407ad - но я все еще немного озадачен тем, как получить доступ к элементам сопрограмм в текущем контексте. Вот часть, которая меня смущает.

Элементы в текущем контексте могут быть получены с использованием приостановленного верхнего уровня свойства coroutineContext только для чтения.

println("Running in ${coroutineContext[CoroutineName]}")

В этом случае CoroutineName является ссылкой на ключ, который отображается на элемент CoroutineName. Я понимаю, что метод get в coroutineContext проверяет тип предоставленного ему ключа c - в данном случае CoroutineName - для получения соответствующего элемента. Я пытаюсь понять, как CoroutineName, или в этом отношении Job, CoroutineExceptionHandler или CoroutineDispatcher, даже доступны для ссылки в текущей области, когда они не являются свойствами приемника CoroutineScope .

Ответы [ 3 ]

0 голосов
/ 16 марта 2020

Реализация глобального свойства coroutineContext присуща c, что означает, что не дается никаких обещаний о том, как оно на самом деле реализовано.

Но в JVM свойство по сути является локальной переменной потока , Когда сопрограмма приостановлена, текущий контекст сопрограммы запоминается в созданном объекте Continuation. Когда сопрограмма возобновляется, контекст копируется обратно из продолжения возобновления в локальную переменную потока, к которой относится свойство coroutineContext.

0 голосов
/ 16 марта 2020

Вот простой код, который вы можете запустить, чтобы уточнить ваше понимание:

fun main() {
    GlobalScope.launch {
        println(this)
        println(GlobalScope)
    }
    Thread.sleep(100)
}

Он напечатает

StandaloneCoroutine{Active}@b4642b3
kotlinx.coroutines.GlobalScope@72445c73

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

Более волшебная часть этого механизма в том, что coroutineContext не просто доступен внутри launch, но в любом suspend fun, как глобальное свойство. Он оценивает тот же контекст, который вы видите в блоке launch.

0 голосов
/ 16 марта 2020

Все эти элементы контекста сопрограммы имеют свойство key, используемое для адресации элементов в контексте сопрограммы (который является своего рода адресным набором). CoroutineName, как и другие элементы контекста, определяет ключ как объект:

companion object Key : Key<CoroutineName>

В Kotlin вы можете получить доступ к сопутствующему объекту класса, используя имя класса:

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

Итак, я думаю, что эти два выражения будут одинаковыми:

coroutineContext[CoroutineName]
coroutineContext[CoroutineName.Key]

Еще один большой вопрос об объектах-компаньонах в SO: Какой смысл называть сопутствующий объект в kotlin

Кстати, вы можете просто нажать Ctrl + клик по CoroutineName in coroutineContext[CoroutineName] в IDEA и посмотреть объявление самостоятельно.

...