简体   繁体   English

Kotlin中的“协程局部”变量

[英]“coroutine local” variables in kotlin

Java has ThreadLocal variables that are nice for running parallel operations without stepping on other threads or per-loop allocations, for example OpenCV uses videoCapture.retrieve(image) , and "image" could be a threadlocal variable. Java具有ThreadLocal变量,非常适合运行并行操作,而无需踩踏其他线程或按循环分配,例如OpenCV使用videoCapture.retrieve(image) ,而“ image”可以是线程videoCapture.retrieve(image)变量。

Does Kotlin have any sense of "coroutine-local" variables? Kotlin是否具有“协程局部”变量的含义? If I wanted to take their counter example but have a counter per coroutine, how would I do that? 如果我想以他们的反例为例,但每个协程都有一个计数器,我该怎么做?

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

If you are looking for ThreadLocal as a performance optimization, to make sure that each thread gets it own copy of some temporary object, then you should continue using ThreadLocal for that purpose. 如果您正在寻找ThreadLocal作为性能优化,以确保每个线程都获得自己的某个临时对象的副本,则应继续为此目的使用ThreadLocal There can be much more coroutines than threads, and keeping a copy of some temporary object for each coroutine may do more harm than good. 协程可能比线程更多,并且为每个协程保留一些临时对象的副本可能弊大于利。

If you are looking for ThreadLocal as a way to pass some context around method invocation, then I strongly suggest to consider explicitly passing this context into your functions or using some dependency injection framework to do that. 如果您正在寻找ThreadLocal作为在方法调用周围传递某些上下文的方法,那么我强烈建议考虑将此上下文显式传递给您的函数或使用某种依赖注入框架来实现。

If you have a rare case where you indeed need to pass some context around, but for some technical reason you cannot pass it explicitly nor you can use DI (that is where you would have used ThreadLocal with threads), you can use CoroutineContext with coroutines. 如果在极少数情况下确实需要传递一些上下文,但是由于某种技术原因,您不能显式传递它,也不能使用DI(也就是将ThreadLocal与线程一起使用的CoroutineContext ),则可以将CoroutineContext与协程CoroutineContext使用。 The steps are: 这些步骤是:

Define your own coroutine context element class using the following template: 使用以下模板定义自己的协程上下文元素类:

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

Create an instance of your element and pass it to the coroutine builder when you start your coroutine. 创建元素实例,然后在启动协程时将其传递给协程生成器。 The following example uses launch coroutine builder, but it works with all of them ( async , produce , actor , etc) 以下示例使用了launch协程生成器,但是可以与所有这些协同工作( asyncproduceactor等)

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

You can combine your context with other context elements using + operators (see "Combining Contexts" in the guide for details) 您可以使用+运算符将上下文与其他上下文元素合并 (有关详细信息,请参见指南中的“合并上下文”

From inside your coroutine code you can always retrieve your element from the coroutineContext . 在协程代码内部,您始终可以从coroutineContext检索元素。 All the standard builders bring the CoroutineScope instance into their scope, which makes its coroutineContext property available. 所有标准构建器都将CoroutineScope实例带入其作用域,这使其coroutineContext属性可用。 If you are deep in the call stack of suspending functions, then you can define your own coroutineContext() helper function to retrieve the current context until it makes its way into the standard library in one of the future updates. 如果您深入了解挂起函数的调用堆栈,则可以定义自己的coroutineContext()帮助函数来检索当前上下文,直到它在将来的更新之一中进入标准库为止。 See KT-17609 for details. 有关详细信息,请参见KT-17609

With the coroutineScope in hand, it is easy to retrieve your element: 有了coroutineScope ,可以轻松检索元素:

val myElement = coroutineScope[MyContextElement]

For those stumbling upon this question nowadays, it seems that the syntax has changed a bit: 对于如今在这个问题上绊脚石的人来说,似乎语法已经有所更改:

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

    companion object Key : CoroutineContext.Key<KCallScope>

}

In order to be CoroutineContext.Key you now need to implement CoroutineContext.Element , which requires you to implement key getter. 为了成为CoroutineContext.Key您现在需要实现CoroutineContext.Element ,这需要您实现key

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM