我仍在努力围绕挂起功能以及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秒才能运行。
有人能阐明为什么三个功能之间的持续时间如此不同吗?
答案 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)个,从而一直创建到基础情况的数据依赖链,因此您无法真正并行化斐波那契。在您的情况下,您需要对相同的成员进行大量的重新计算,因此可以通过并行性进行改进,但是仍然远远不能正确实现单线程解决方案。