I am learning about coroutines and reading the Coroutines and channels − tutorial. I have also read this article which explains a common misconception.
From what I understand so far, coroutines do not inherently turn blocking code into non-blocking/asynchronous code.
I am interested in this part of the tutorial where we introduce suspending functions and concurrency.
What I don’t understand is how the suspending function provided by the retrofit interface knows at what point to suspend and yield control of the thread to some other coroutine. For example, what will be written in the implementation of this function which indicates to the coroutine scope which calls this suspending function to pause and resume at the correct time.
interface GitHubService {
@GET("orgs/{org}/repos?per_page=100")
suspend fun getOrgRepos(
@Path("org") org: String
): List<Repo>
}
How do I write my own non-blocking code that others can call using suspending functions inside a coroutine and get the non-blocking behavior. Something like
suspend fun getOrgRepos(..) {
// make network request and somehow suspend/yield control
// waiting for result
// let the caller know I am ready to be resumed
}
Follow up:
From Roman’s article:
Suspending functions add a new dimension to code design. It was blocking/non-blocking without coroutines and now there is also suspending/non-suspending on top of that
Does this mean that blocking/non-blocking and suspending/non-suspending are completely orthogonal to teach other. I cannot resolve this mentally.
Is it correct to say: A piece of code will not block the calling thread if:
- It is called using a coroutine builder like
async, launch, ~~runBlocking(probably not)~~
- The function called inside the builder has the
suspend
modifier - The implementation/body of the function has followed some conventions. It is not actually blocking the thread and has also somehow communicated to the coroutine context details about when to suspend and resume.