Conceptual question: ```suspend fun foo() = corout...
# coroutines
z
Conceptual question:
Copy code
suspend fun foo() = coroutineScope {
    val b = async { blockingHttpRequest() }
    val s = async { suspendedHttpRequest() }
    Pair(b.await(), s.await())
}

fun blockingHttpRequest() { ... }
suspend fun suspendedHttpRequest() { ... }
Given two long-running functions making network requests, one which is a normal blocking function, the other a suspend function, is there any difference between the execution of the two functions each within their own coroutine? What would be the benefit of using a suspended version? I just read the docs four times over and can't find an answer.
s
• The blocking version will occupy a thread for the full duration of the request. Threads use a lot of resources and are thus limited in number. Blocking a thread that belongs to a coroutine dispatcher is generally a bad idea, because the coroutine dispatcher may eventually run out of threads to schedule new work, even when the CPU is not fully utilised. • Assuming you’re using a true non-blocking HTTP client, the suspending version will only occupy a thread when preparing the request and receiving the response. While the request is in flight, the thread will be returned to the coroutine dispatcher which can use it to run other coroutines.
z
So hypothetically, if all that were available was a blocking client, the solution would be to just create a new thread, or allocate a custom thread pool?
s
Actually the built-in IO dispatcher is designed for exactly that kind of scenario. It deliberately has a larger thread pool so that it can tolerate blocking calls.
So if you want to make a blocking call from a coroutine, you can wrap it in
withContext(<http://Dispatchers.IO|Dispatchers.IO>)
. That will free up the calling thread while the blocking call takes place on one of the dedicated threads owned by the IO dispatcher. (In practice there might not be an actual thread switch, due to some clever implementation).
z
thank you