Java有ThreadLocal变量,这些变量非常适合在不踩其他线程或按循环分配的情况下运行并行操作,例如OpenCV使用videoCapture.retrieve(image)
,"image"可以是线程本地变量。
Kotlin对"协程局部"变量有任何意义吗?如果我想举他们的反例,但每次合作都有一个计数器,我该怎么做?
for (i in 1..1_000_000)
thread(start = true) {
c.addAndGet(i)
}
如果您正在寻找ThreadLocal
作为性能优化,以确保每个线程都能获得某个临时对象的自己的副本,那么您应该继续为此目的使用ThreadLocal
。协同程序可能比线程多得多,为每个协同程序保留一个临时对象的副本可能弊大于利。
如果您正在寻找ThreadLocal
作为一种在方法调用周围传递一些上下文的方式,那么我强烈建议您考虑将此上下文显式传递到您的函数中,或者使用一些依赖注入框架来实现这一点。
如果您有一种罕见的情况,您确实需要传递一些上下文,但由于某些技术原因,您不能显式传递它,也不能使用DI(这就是您将ThreadLocal
与线程一起使用的情况),那么您可以将CoroutineContext
与协程一起使用。步骤是:
使用以下模板定义您自己的协同程序上下文元素类:
class MyContextElement : AbstractCoroutineContextElement(MyContextElement) {
companion object Key : CoroutineContext.Key<MyContextElement>
// you state/code is here
}
创建元素的实例,并在启动协同程序时将其传递给协同程序生成器。以下示例使用launch
协程生成器,但它可以与所有协程生成器(async
、produce
、actor
等)一起使用
launch(MyContextElement()) {
// the code of your coroutine
}
您可以使用+
运算符将您的上下文与其他上下文元素组合(有关详细信息,请参阅指南中的"组合上下文")
从协同程序代码内部,您总是可以从coroutineContext
中检索元素。所有的标准构建器都将CoroutineScope实例带入其作用域,从而使其coroutineContext
属性可用。如果您深入到挂起函数的调用堆栈中,那么您可以定义自己的coroutineContext()
辅助函数来检索当前上下文,直到它在将来的更新中进入标准库。详见KT-17609。
有了coroutineScope
,很容易检索您的元素:
val myElement = coroutineScope[MyContextElement]
对于那些现在偶然发现这个问题的人来说,语法似乎发生了一些变化:
class MyContextElement : AbstractCoroutineContextElement(MyContextElement), CoroutineContext.Element {
override val key = Key
companion object Key : CoroutineContext.Key<KCallScope>
}
为了成为CoroutineContext.Key
,您现在需要实现CoroutineContext.Element
,这要求您实现key
getter。