问题描述
目前,我正在尝试通过改进不同 dispatcher 和上下文的使用来优化我的应用程序性能。我偶然发现的一个问题是,如果我在带有 IO dispatcher 的协程中启动一个挂起函数,其他所有函数是否也会在同一个 dispatcher 中执行?
示例
fun doSomething() {
viewmodelScope.launch(dispatchers.IO) {
getUserData(viewmodelScope)
}
}
fun getUserData(innerScope: Coroutinescope) {
workerList.startUserDataWorker()
observeUserData(innerScope) // suspend function,is this called inside the IO Dipatcher?
}
// Will this be called inside the IO dispatcher?
private suspend fun observeUserData(innerScope: Coroutinescope) {
observerWorkerStateAndPassData(workerList.userDataWorkInfo,USER_DATA_OUTPUT_OPTION).collect { status ->
when(status) {
is Status.Loading -> {
_userDataState.postValue(Status.loading())
}
is Status.Success -> {
// Will getShippingAddressList() also be called on the IO dispatcher?
_userDataState.postValue(Status.success(getShippingAddressList()))
}
is Status.Failure -> {
_userDataState.postValue(Status.Failed(status.message.toString()))
}
}
}
}
// Getting Address from the local room cache. Is this called on the IO dispatcher?
private suspend fun getShippingAddressList(): List<UserDeliveryAddress> {
val uncachedList = userAddressDao.getAllAddress(UserAddressCacheOrder.SHIPPING)
return userAddressCacheMapper.mapFromEntityList(uncachedList)
}
解决方法
在调用挂起函数时,您使用的调度程序无关紧要。它仅在调用阻塞函数时相关。挂起不使用调度程序线程。
例外:
- 您的挂起功能设计不当,实际上会阻塞。
- 如果您在多个同时进行的协程中处理对象,则会产生并发影响。例如,如果您只使用 Main 或单线程调度程序触摸特定对象,则不必担心多个线程同时触摸它。我认为要进行适当的封装,您应该始终使用
withContext(mySingleThreadDispatcher)
包装相关对象的这些用法,这样哪个调度程序调用您的挂起函数仍然无关紧要。
在您的示例中,调度程序调用 observeUserData
的内容无关紧要,因为该函数在收集时将无限期挂起。当它收集时,它只调用非阻塞、线程安全的函数 LiveData.postValue()
。