来自 Kotlin Concurrancy HandsOn 的关于 Kotlin/Native 中冻结的查询

Moh*_*hit 2 kotlin-native kotlin-multiplatform kotlin-multiplatform-mobile

我正在关注此处的Kotlin/Native Concurrency 实践。我无法理解最后一个示例,为什么“上面修改后的 saveToDb 函数现在处理后台调用,并且仅捕获函数参数。这不会冻结父类

class CountingModelSafer{
    var count = 0

    fun increment(){
        count++
        saveToDb(count)
    }

    private fun saveToDb(arg:Int) = background {
        println("Doing db stuff with $arg, in main $isMainThread")
    }
}
Run Code Online (Sandbox Code Playgroud)

[请注意,在这些示例中,在背景内部,传递的 lambda 被冻结]

下面的代码片段会导致整个 CountingModel 被冻结,但上面的代码片段不会被冻结。有人可以帮我理解为什么会这样吗?

class CountingModel{
    var count = 0

    fun increment(){
        count++
        background {
            saveToDb(count)
        }
    }

    private fun saveToDb(arg:Int){
        //Do some db stuff
        println("Saving $arg to db")
    }
}
Run Code Online (Sandbox Code Playgroud)

Kev*_*gan 5

当然。我写了示例,所以让我尝试解释一下。

        background {
            saveToDb(count)
        }
Run Code Online (Sandbox Code Playgroud)

background函数采用 lambda 参数。Lambda 可以“捕获”状态并影响它。我的意思是,忘记“冻结”,您通常会期望更改 的值count会更改源值。因此,如果我们忘记“冻结”,则 ifcount从 0 开始,则以下结果将count是 1:

        background {
            count++
        }
Run Code Online (Sandbox Code Playgroud)

为了实现这一点,lambda 需要引用count,并且引用count意味着您将尊重持有它的类。更正式地说,代码应如下所示:

        background {
            this.count++
        }
Run Code Online (Sandbox Code Playgroud)

我们不需要声明this.count,但这只是因为this是假设的。

Lambda 需要访问它们引用的状态,而这一切都不是魔法。Lambda 具有状态,即它们捕获的对象。冻结状态是指被冻结者接触到的所有状态。对于 lambda 函数,这意味着代码引用的任何内容。

在这种情况下:

    private fun saveToDb(arg:Int) = background {
        println("Doing db stuff with $arg, in main $isMainThread")
    }
Run Code Online (Sandbox Code Playgroud)

arg:Int是一个参数。arg被冻结,但 lambda 中没有任何内容捕获父类。如果你this.arg这样写的话就会出错。arg是本地的。冻结它不会级联到父类。

我开始编写一个 Intellij/AS 插件来帮助警告您这些可能的情况,因为这是最有可能让人绊倒的事情,但 Kotlin 团队告诉我,他们决定取消这种内存模型。因此,该插件的工作停止了。明年某个时候,这将不再是问题。

然而,学习这种记忆模型是有用的。从线程的角度来看,开发人员往往会随意做一些危险的事情。Kotlin/Native 限制性线程模型迫使您重新思考如何构建代码。这不一定是坏事。

但我离题了。模式正在发生变化。与此同时,请注意你的捕获状态。