【问题标题】:"coroutine local" variables in kotlinkotlin 中的“协程本地”变量
【发布时间】:2018-03-22 11:07:07
【问题描述】:

Java 有 ThreadLocal 变量,可以很好地运行并行操作,而无需踩到其他线程或按循环分配,例如 OpenCV 使用 videoCapture.retrieve(image),“image”可以是线程局部变量。

Kotlin 对“协程本地”变量有任何意义吗?如果我想以他们的反例为例,但每个协程都有一个计数器,我该怎么做?

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

【问题讨论】:

标签: kotlin coroutine kotlin-coroutines


【解决方案1】:

如果您正在寻找 ThreadLocal 作为性能优化,以确保每个线程都获得它自己的某个临时对象的副本,那么您应该继续为此目的使用 ThreadLocal。协程可能比线程多得多,并且为每个协程保留一些临时对象的副本可能弊大于利。

如果您正在寻找 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" in the guide

在您的协程代码中,您始终可以从coroutineContext 中检索您的元素。所有标准构建器都将CoroutineScope 实例纳入其范围,这使其coroutineContext 属性可用。如果您深入到挂起函数的调用堆栈中,那么您可以定义自己的 coroutineContext() 帮助函数来检索当前上下文,直到它在未来的更新之一中进入标准库。详情请见KT-17609

有了coroutineScope,很容易检索你的元素:

val myElement = coroutineScope[MyContextElement]

【讨论】:

    【解决方案2】:

    对于现在遇到这个问题的人来说,语法似乎发生了一些变化:

    class MyContextElement : AbstractCoroutineContextElement(MyContextElement), CoroutineContext.Element {
        override val key = Key
    
        companion object Key : CoroutineContext.Key<KCallScope>
    
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-29
      • 2021-09-24
      • 2018-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多