为什么需要更改协同程序中的分派器?

I've been going through this codelab to learn about coroutines. One thing that still isn't clear to me is that why do we need to change dispatchers to ensure that we don't block the main/UI thread? If coroutines are light-weight threads, then why can't I invoke thread-blocking functions (whether they're suspending or not) within a coroutine when I'm already on the main thread?

如果我编写以下代码,则代码实验室对此进行了总结:

// Repository.kt
suspend fun repoRefreshTitle() {
    delay(500)
}

//ViewModel.kt
fun vmRefreshTitle() {
   viewModelScope.launch {
       _spinner.value = true
       repository.repoRefreshTitle()
   }
}

...then this won't block the main thread. delay() is a suspend function, so the coroutine created by viewmodelScope.launch will be paused until the 500ms passes. The main thread won't be blocked though.

However, if I refactor repoRefreshTitle() to the following:

suspend fun repoRefreshTitle() {
    val result = nonSuspendingNetworkCall()
}

...然后网络调用实际上将在主线程上完成。那是对的吗?我将不得不更改为另一个调度程序,以将工作分流到IO线程:

suspend fun repoRefreshTitle() {
    withContext(Dispatchers.IO) {
        val result = nonSuspendingNetworkCall()
    }
}

我必须以某种方式过分简化。我已经足够接受协程了吗?为什么必须切换调度程序?