协程值得与类型映射一起使用吗?
Are coroutines worth using with type mapping?
是否值得调用协程来执行类型映射操作?或者它会导致过多的代码膨胀 and/or 开销?
所以场景如下:
LiveData<List<A>>
的回购 returns 个对象
视图需要 LiveData<<List<GUI_A>>
类型的对象
ViewModel
通过使用 Transformations.map
和来自 repo 的源 LiveData<A>
公开 LiveData<GUI_A>
。
Transformations.map
代码看起来像这样
fun doSomethingWithRepoData(repoData: LiveData<List<A>>): LiveData<List<GUI_A>> =
Transformations.map(repoData) {
it.map { GUI_A.fromRepoObject(it) }
}
函数 fromRepoObject
仅将第一个对象的属性映射到第二个对象的新实例。
想法是在map函数中使用协程来提高性能;但我不知道这是否值得麻烦:
fun doSomethingWithRepoData(repoData: LiveData<List<A>>): LiveData<List<GUI_A>> =
Transformations.map(repoData) {
it.map { async { GUI_A.fromRepoObject(it) } }
.map { it.await() }
}
我讨厌的最终答案是这取决于。
切换线程的上下文不是免费的,这样做会产生一些累积的开销,因此在考虑一件事或另一件事之前,您必须注意数据的大小。
- 映射 15 个元素?可能不值得。
- 映射1000?可能是!他们是否有嵌套的列表和地图也应该被映射?
- 映射1_000_000?绝对!
我们还应该注意我们的映射实现。
给出的例子:
fun doSomethingWithRepoData(repoData: LiveData<List<A>>): LiveData<List<GUI_A>> =
Transformations.map(repoData) {
it.map { async { GUI_A.fromRepoObject(it) } }
.map { it.await() }
}
不要这样做。
你看; LiveData
确保观察 LiveData
的代码在主线程上是 运行。一方面这很好,因为它确保了主线程的安全,但另一方面它在这种情况下是 "bad",因为主线程在推送值之前等待所有协程完成它们的映射操作。
一个更聪明的方法,假设我们在 ViewModel
可能是:
class SampleVM: ViewModel(){
fun doSomethingWithRepoData(repoData: LiveData<List<A>>): LiveData<List<GUI_A>> =
Transformations.switchMap(repoData) { listA ->
val result = MutableLiveData<List<GUI_A>>()
// Don't block the UI thread by running in a coroutine
viewModelScope.launch {
listA
// Parallelize computation
.map { async(Dispatchers.Default) { GUI_A.fromRepoObject(it) }
// The viewModelScope job will await for all coroutines to finish mapping
.map { it.await() }
// Post the result to into the live data
.let { result.postValue(it) }
}
result
}
}
是否值得调用协程来执行类型映射操作?或者它会导致过多的代码膨胀 and/or 开销?
所以场景如下:
LiveData<List<A>>
的回购 returns 个对象
视图需要
LiveData<<List<GUI_A>>
类型的对象
ViewModel
通过使用Transformations.map
和来自 repo 的源LiveData<A>
公开LiveData<GUI_A>
。
Transformations.map
代码看起来像这样
fun doSomethingWithRepoData(repoData: LiveData<List<A>>): LiveData<List<GUI_A>> =
Transformations.map(repoData) {
it.map { GUI_A.fromRepoObject(it) }
}
函数 fromRepoObject
仅将第一个对象的属性映射到第二个对象的新实例。
想法是在map函数中使用协程来提高性能;但我不知道这是否值得麻烦:
fun doSomethingWithRepoData(repoData: LiveData<List<A>>): LiveData<List<GUI_A>> =
Transformations.map(repoData) {
it.map { async { GUI_A.fromRepoObject(it) } }
.map { it.await() }
}
我讨厌的最终答案是这取决于。
切换线程的上下文不是免费的,这样做会产生一些累积的开销,因此在考虑一件事或另一件事之前,您必须注意数据的大小。
- 映射 15 个元素?可能不值得。
- 映射1000?可能是!他们是否有嵌套的列表和地图也应该被映射?
- 映射1_000_000?绝对!
我们还应该注意我们的映射实现。
给出的例子:
fun doSomethingWithRepoData(repoData: LiveData<List<A>>): LiveData<List<GUI_A>> =
Transformations.map(repoData) {
it.map { async { GUI_A.fromRepoObject(it) } }
.map { it.await() }
}
不要这样做。
你看; LiveData
确保观察 LiveData
的代码在主线程上是 运行。一方面这很好,因为它确保了主线程的安全,但另一方面它在这种情况下是 "bad",因为主线程在推送值之前等待所有协程完成它们的映射操作。
一个更聪明的方法,假设我们在 ViewModel
可能是:
class SampleVM: ViewModel(){
fun doSomethingWithRepoData(repoData: LiveData<List<A>>): LiveData<List<GUI_A>> =
Transformations.switchMap(repoData) { listA ->
val result = MutableLiveData<List<GUI_A>>()
// Don't block the UI thread by running in a coroutine
viewModelScope.launch {
listA
// Parallelize computation
.map { async(Dispatchers.Default) { GUI_A.fromRepoObject(it) }
// The viewModelScope job will await for all coroutines to finish mapping
.map { it.await() }
// Post the result to into the live data
.let { result.postValue(it) }
}
result
}
}