暂停功能在执行时间上有很大的不同

时间:2019-05-02 14:57:53

标签: android kotlin-coroutines

我仍在努力围绕挂起功能以及IO绑定和CPU绑定挂起功能之间的区别(如果有)。

我正在主线程中启动协程,并以不同的方式运行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秒才能运行。

有人能阐明为什么三个功能之间的持续时间如此不同吗?

1 个答案:

答案 0 :(得分:1)

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

这是您的基本情况,斐波那契的效率极低。它完全独立于fib(x - 1)来计算fib(x - 2),从而导致函数调用呈指数级增长。计算fib(24)大约需要(黄金比率) 24 = 103682次呼叫。

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) }

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