Reputation: 143
i have the following code in Kotlin
import kotlinx.coroutines.experimental.async
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.runBlocking
fun main(args: Array<String>) {
runBlocking {
val async1 = async {
println("1st")
delay(2000)
println("1st end")
}
val async2 = async {
println("2nd")
delay(1000)
println("2nd end")
}
async1.await()
async2.await()
println("end")
}
}
The output is
1st
2nd
2nd end
1st end
end
My understanding was, that await()
is a suspending function, meaning the execution is "paused" there. So i thought, that actually first async1
would be executed, and THEN async2
would be executed. So i expected the output to be
1st
1st end
2nd
2nd end
end
What obviously happened was, that both async1
and async2
where executed in parallel, which can be seen as the output of async1
is sandwiched between the outputs of async2
.
So my concrete question is now: Why did Kotlin not suspend on async1
, but concurrently started async2
?
Upvotes: 1
Views: 2436
Reputation: 200148
Why did Kotlin not suspend on
async1
, but concurrently startedasync2
?
async
spawns a new task in the background. The task starts executing right away. You have no control over its suspension and there's a whole class of use cases where it never gets suspended. We often use async
to submit blocking tasks to a thread pool.
await
suspends the current coroutine until the task has completed and produced its result. It has no effect on the execution of the task. The task will run to completion even if you never call await
.
If you specifically want to fire the task only when you call await
, you can specify start = LAZY
:
runBlocking {
val async1 = async(start = LAZY) {
println("1st")
delay(2000)
println("1st end")
}
val async2 = async(start = LAZY) {
println("2nd")
delay(1000)
println("2nd end")
}
async1.await()
async2.await()
println("end")
}
This reliably prints in the order you expected.
Upvotes: 2
Reputation: 4952
await()
will suspend coroutine it run's in - which is your main block (and a thread runBlocking()
is running, because it's blocking), so async2.await()
will not be called, unless async1
is finished.
But since execution of async()
function is started immediately and will be executed by default on background thread pool, it will not be blocked.
You can check it by adding
async1.await()
println("between")
async2.await()
and see, that "between" will always be printed after "1st end"
If you want coroutines to run sequentially - use runBlocking()
builder (or in most cases no need to use coroutines at all for such cases)
The idea of async/await is to run tasks in parallel and don't block other tasks while you waiting for results of one of them.
Upvotes: 2