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

Is every function that is called inside launch(Dispatchers.IO) also called in the IO Dispatcher?

目前,我正在尝试通过改进不同调度程序和上下文的使用来优化我的应用程序性能。我偶然发现的一个问题是,如果我在带有 IO 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().