android 在launch(Dispatchers.IO)中调用的每个函数是否也在IO Dispatcher中调用?

5f0d552i  于 2023-03-06  发布在  Android
关注(0)|答案(1)|浏览(248)

目前,我正在尝试通过提高不同Dispatcher和上下文的使用来优化应用性能。我偶然发现的一个问题是,如果我在带有IO Dispatcher的协程中启动一个suspend函数,其他函数是否也会在同一个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)
}
juzqafwq

juzqafwq1#

除了下面的例外,你使用的调度器在调用一个suspend函数时是无关紧要的。它只在调用blocking函数时是相关的。挂起不使用调度器线程。
例外情况:

  • 你的suspend函数设计不当,它实际上阻塞了。这打破了协程的惯例。suspend函数不应该阻塞。
  • 也许你的suspend函数没有阻塞,但是它触及了只允许在特定线程上使用的对象,例如Android上的大多数View类。对于这种情况没有官方约定--你可以跳过用withContext(Dispatchers.Main) Package 函数内容,从而将main-only限制从view类传递到suspend函数调用者。既然你可以使用withContext来避免潜在的问题,至少当suspend函数是公共的时候,你也可以使用Dispatchers.Main.immediate来避免不必要的线程切换。
  • 如果你在多个并发协程中处理对象,并发性的含义。例如,如果你只使用Main或单线程调度程序访问一个特定的对象,你不必担心多个线程同时访问它。我主张正确的封装,您应该始终使用withContext(mySingleThreadDispatcher) Package 关注对象的这些使用,这样哪个调度程序正在调用就仍然无关紧要暂停功能。

在你的例子中,哪个调度器调用observeUserData并不重要,因为这个函数在它收集的时候会无限期地挂起,而且当它收集的时候,它只调用非阻塞的线程安全函数LiveData.postValue()

相关问题