"Coroutine local" переменные в kotlin

Java имеет переменные ThreadLocal, которые хороши для выполнения параллельных операций без перехода на другие потоки или распределения по каждому циклу, например, OpenCV использует videoCapture.retrieve(image) , а «изображение» может быть переменной threadlocal.

Есть ли у Котлина какое-либо чувство «сопрограмм-локальных» переменных? Если бы я хотел принять их встречный пример, но имел счетчик на сопрограмму, как бы я это сделал?

 for (i in 1..1_000_000) thread(start = true) { c.addAndGet(i) } 

Если вы ищете ThreadLocal как оптимизацию производительности, чтобы убедиться, что каждый поток получает свою собственную копию некоторого временного объекта, вам следует продолжить использование ThreadLocal для этой цели. Может быть гораздо больше сопрограмм, чем потоки, и сохранение копии какого-либо временного объекта для каждой сопрограммы может принести больше вреда, чем пользы.

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

Если у вас есть редкий случай, когда вам действительно нужно пройти какой-то контекст, но по какой-то технической причине вы не можете передать его явно, и вы не можете использовать DI (именно там, где вы бы использовали ThreadLocal с потоками), вы можете использовать CoroutineContext с сопрограммами , Шаги:

Определите свой собственный класс элемента контекста coroutine, используя следующий шаблон:

 class MyContextElement : AbstractCoroutineContextElement(MyContextElement) { companion object Key : CoroutineContext.Key<MyContextElement> // you state/code is here } 

Создайте экземпляр вашего элемента и передайте его разработчику coroutine при запуске своей сопрограммы. В следующем примере используется компоновщик launch coroutine, но он работает со всеми из них ( async , produce , actor и т. Д.),

 launch(MyContextElement()) { // the code of your coroutine } 

Вы можете комбинировать свой контекст с другими элементами контекста с помощью операторов + (подробнее см. «Объединение контекстов» в руководстве )

Изнутри кода coroutine вы всегда можете извлечь свой элемент из coroutineContext . Все стандартные разработчики приносят экземпляр CoroutineScope в свой объем, что делает его свойство coroutineContext доступным. Если вы глубоко в стеке вызовов приостанавливающих функций, то вы можете определить свою собственную вспомогательную функцию coroutineContext() для извлечения текущего контекста, пока он не войдет в стандартную библиотеку в одном из будущих обновлений. Подробнее см. KT-17609 .

С помощью coroutineScope в руке легко извлечь элемент:

 val myElement = coroutineScope[MyContextElement]