Kotlin中的"协程局部"变量

3

Java有ThreadLocal变量,非常适合在不干涉其他线程或循环分配的情况下执行并行操作,例如OpenCV使用videoCapture.retrieve(image),“image”可以是一个ThreadLocal变量。

Kotlin是否有“协程本地”变量的概念?如果我想采用它们的反例,但对于每个协程都有一个计数器,我该怎么做?

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

我认为你可以使用CoroutineContext: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.experimental/-coroutine-context/ - marstran
2个回答

10
如果你正在寻找一种性能优化的方式,确保每个线程都可以获得自己的某个临时对象的副本,那么你应该继续使用 ThreadLocal。在协程中可能会有比线程更多的协程,并为每个协程保留某个临时对象的副本可能会弊大于利。
如果你正在寻找一种传递方法调用上下文环境的方式,我强烈建议考虑明确传递此上下文环境到你的函数中或使用某个依赖注入框架来实现。
如果你确实需要传递一些上下文环境,但由于某些技术原因不能显式地传递它,也不能使用 DI(这就是你曾经在线程中使用 ThreadLocal 的地方),则可以在协程中使用 CoroutineContext。步骤如下:
使用以下模板定义自己的协程上下文元素类:
class MyContextElement : AbstractCoroutineContextElement(MyContextElement) {
    companion object Key : CoroutineContext.Key<MyContextElement>
    // you state/code is here
}

在启动协程时,创建您的元素实例并将其传递给协程构建器。以下示例使用 launch 协程构建器,但它适用于所有构建器(asyncproduceactor 等)。

launch(MyContextElement()) {
    // the code of your coroutine
}
您可以使用+运算符将您的上下文与其他上下文元素组合在一起(有关详细信息,请参见指南中的"Combining Contexts")。
从协程代码内部,您始终可以从coroutineContext中检索您的元素。所有标准构建器都会将CoroutineScope实例引入其作用域,从而使其coroutineContext属性可用。如果您深入挂起函数的调用堆栈中,则可以定义自己的coroutineContext()帮助函数来检索当前上下文,直到它在未来更新之一的标准库中发挥作用。有关详细信息,请参见KT-17609
有了coroutineScope,很容易检索您的元素 :
val myElement = coroutineScope[MyContextElement]

1

对于那些现在遇到这个问题的人来说,语法似乎有点改变了:

class MyContextElement : AbstractCoroutineContextElement(MyContextElement), CoroutineContext.Element {
    override val key = Key

    companion object Key : CoroutineContext.Key<KCallScope>

}

为了成为CoroutineContext.Key,现在需要实现CoroutineContext.Element,并要求您实现key getter。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接