android - 具有挂起功能的执行时间存在巨大差异

标签 android kotlin-coroutines

我仍在努力思考挂起函数以及 IO 绑定(bind)挂起函数和 CPU 绑定(bind)挂起函数之间的区别(如果有的话),以及其他事情。

我在主线程中启动协程并以不同的方式运行 cpu 密集型函数以查看会发生什么。

class TestActivity : AppCompatActivity(), CoroutineScope {
    private val job = Job()
    override val coroutineContext: CoroutineContext
        get() = job + Dispatchers.Main

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        launch {
            val start = System.currentTimeMillis()
            Log.d("test", "start: $start")

            fib(24)

            val finish = System.currentTimeMillis()
            Log.d("test", "finish: $finish")
            Log.d("test", "duration: ${finish - start}")
        }
    }

我已经尝试了 fib 函数的这三种变体:

private fun fib(x: Int): Int =
    if (x <= 1) x else fib(x - 1) + fib(x - 2)

常规方式:xml 不会立即膨胀,函数需要 0.1 秒才能运行。

private suspend fun fib(x: Int): Int =
    if (x <= 1) x else fib(x - 1) + fib(x - 2)

常规方式+suspend关键字:xml不会立即膨胀,函数运行需要1.3秒。

private suspend fun fib(x: Int): Int =
    withContext(Dispatchers.Default) { if (x <= 1) x else fib(x - 1) + fib(x - 2) }

常规方式 + suspend 关键字 + 用 withContext(Dispatchers.Default) 包裹它:xml 立即膨胀,函数需要 25 秒才能运行。

谁能解释一下为什么这三个功能的持续时间有如此大的差异?

最佳答案

private fun fib(x: Int): Int =
    if (x <= 1) x else fib(x - 1) + fib(x - 2)

这是您的基本情况,斐波那契的一种极其低效的递归实现。它完全独立于 fib(x - 2) 计算 fib(x - 1),这导致函数调用呈指数级增长。为了计算 fib(24),它进行了大约(黄金比例)24 = 103,682 次调用。

private suspend fun fib(x: Int): Int =
    if (x <= 1) x else fib(x - 1) + fib(x - 2)

从语义上讲,这与上面的完全相同。声明为可挂起但挂起点为零的函数。由于可挂起函数固有的 CPS 转换开销,它速度较慢。

private suspend fun fib(x: Int): Int =
    withContext(Dispatchers.Default) { if (x <= 1) x else fib(x - 1) + fib(x - 2) }

在这里您实际上实现了一些并行性,但并行加速与分派(dispatch)非常小的工作 fragment 的开销相比相形见绌。此外,由于要计算斐波那契数列的第 n 个成员,您需要已经计算出第 (n - 1) 个和 (n - 2) 个,从而创建一直到基本情况的数据依赖链,你不能真的并行斐波那契。在您的情况下,您对相同的成员进行了大量重新计算,因此可以通过并行性加以改进,但仍远未达到正确实现的单线程解决方案。

关于android - 具有挂起功能的执行时间存在巨大差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55955172/

相关文章:

android - 数据绑定(bind)中的开关盒

android - 如果从协程调用非挂起函数会发生什么?

android - 尝试使用 Paging Library 3 时在 Gradle 中发现重复的类

android-room - 每当设备恢复事件状态时,Kotlin Coroutines Flow with Room 再次运行

android - Kotlin接口(interface)无法实例化!接口(interface)名称 : kotlinx. 协程.Deferred

Android NotificationChannel 在运行时请求多个 channel 的权限?

java - 从 Java 代码调用 C++ 的问题 (Android)

android - 如何检查对象关系是否为空?

android - 取消广播接收器中的协程

android - 如何在向下滚动后到达 “SliverPersistentHeader” 的第一项之前将 “SliverList” 固定在顶部?