可以使用 redundant/nested withContext 调用吗?

Is it OK to use redundant/nested withContext calls?

我有一个用Kotlin写的个人项目,养成了非常慷慨的使用withContext(...)的习惯。在调用可能与 I/O.

相关的任何内容时,我倾向于使用 withContext(Dispatchers.IO)

例如:

suspend fun getSomethingFromDatabase(db: AppDatabase) = withContext(Dispatchers.IO) {
    return // ...
}

suspend fun doSomethingWithDatabaseItem(db: AppDatabase) {
    val item = withContext(Dispatchers.IO) {
        getSomethingFromDatabase(db)
    }
    // ...
}

在第二个函数中可以看到多余的withContext(Dispatchers.IO)。我在这里格外小心,因为如果 getSomethingFromDatabase 是否切换到适当的上下文,我可能不会 know/remember。这会影响性能吗?这很糟糕吗?处理 Dispatchers 的惯用方式是什么?

注意:我知道用这种方式在不同的上下文之间切换是完全没问题的,但是这个问题具体是关于使用相同的上下文

除了调用需要特定上下文的代码外,您不需要 withContext。因此 withContext(Dispatchers.Main) 只应在您使用需要主线程的 UI 函数时使用。并且你应该只在调用 blocking IO 相关代码时使用 withContext(Dispatchers.IO)

适当的挂起函数不会阻塞 (see Suspending convention section here),因此,您应该永远不会必须指定调度程序来调用挂起函数。例外情况是,如果您正在使用其他人的代码或 API 而他们错误地使用了挂起函数!

我不知道你的 AppDatabase class 是什么,但如果设计合理,它将公开挂起函数而不是阻塞函数,所以你应该不需要 withContext 来检索值从中。但是,如果它确实公开了用于检索项目的阻塞函数,那么您的第一个函数的代码是正确的。

你的第二个函数绝对不需要 withContext 因为它只是用它来调用我可以看到的东西是一个挂起函数。

至于是否可以使用冗余上下文切换...除了可能浪费一点点时间和内存上下文切换以及无缘无故分配lambda之外,它没有任何伤害。而且它会降低你的代码的可读性。