And*_*rew 2 android kotlin kotlin-coroutines
目前,我正在尝试 kotlin 协程,我问自己一个问题:使用协程时是否有显着的性能提升?让我们看一些(理论)例子:
val myUnsortedList = listOf(1, 2, 5, 6, 3, 10, 100)
fun doStuffWithSorted(list: List<Int>) { ... }
// Without coroutine
val sortedList = myUnsortedList.sorted()
doStuffWithSorted(sortedList)
coroutineScope {
launch {
val sortedList = myUnsortedList.sorted()
doStuffWithSorted(sortedList)
}
}
Run Code Online (Sandbox Code Playgroud)
fun doSomeHeavyOperations() { // doing heavy Operations but non blocking }
fun main() { doSomeHeavyOperations() }
//////////////// VERSUS //////////////////////
suspend fun doSomeHeavyOperations() { // doing heavy Operations but non blocking }
suspend fun main() {
coroutineScope {
launch {
doSomeHeavyOperations()
}
}
}
Run Code Online (Sandbox Code Playgroud)
还有更多示例,也许你们中的一个可以提供一些,建议使用协程。所以我的最后一个问题是(包括上面的问题):什么时候应该考虑用协程来优化代码性能,什么时候代价大于获得的性能?
协程主要是一种涉及大量等待的计算工具,想想同步执行的网络调用。在这些情况下,调用线程除了等待服务器的响应之外什么也不做。
为了消除这个等待问题,我们使用异步编程,又称回调。因此,您启动一个网络调用并指定一个回调,一旦结果准备好就会调用该回调。但回调模型有它自己的问题,即回调地狱,如下面的代码所示。
fun someAPICalls(){
getToken(){ token ->
login(token) { userID ->
getUser(userID){ user ->
// Save user in DB
// This nesting can be even deeper
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,这段代码不被认为是可管理的。借助 kotlin 的挂起函数,所有这些都简化为
fun someAPICalls() = viewModelScope.launch{
val token = getToken() // suspending function calls (Retrofit, Room)
val userId = login(token)
val user = getUser(userId)
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,这与顺序代码的编写方式非常接近。
尽管还有其他选项(RX等)可用于解决回调问题,但它们确实引入了您需要学习的自己的语义。另一方面,编写协程代码与顺序代码没有太大不同,您只需要学习一些基本构造(调度程序、构建器等),这使得协程成为这种情况下的最佳选择。
除此之外,还有一些其他场景可以有效地使用协程,其中一个用例就是 Android 等 UI 框架中使用的线程卸载实践。当您想要执行长时间运行的 CPU 密集型操作时,您不会在 UI 线程上执行此操作,而是将该操作卸载到后台线程。这也可以使用协程构建器之一非常干净地完成,例如lifecycleScope.launch(Dispatchers.Default) {}
协程是线程之上的抽象,它需要线程来执行,就像线程需要CPU核心来执行一样。因此,协程管理会带来一定的开销,因此,如果您需要执行长时间运行的 CPU 密集型操作,并且可能需要使用多个线程,那么最好使用线程(Java ExecutorService 等)。