Hi, I watched "Introduction to Kotlin Coroutines video" and understand that Kotlin coroutens is designed for sequential execution default.
So, we often define suspending functions for sequentially execution and sometimes use coroutine builders for concurrent execution.
In this case, I have a question what's a good design for delivering cancellation.
Sample code is here.
fun main(args: Array<String>) = runBlocking {
println("start")
val job = launch(coroutineContext) { runParallelTasks() }
delay(1000)
job.cancel()
delay(1500)
println("Done")
}
suspend fun runParallelTasks() {
val job1 = launch(CommonPool) { task1() }
val job2 = launch(CommonPool) { task2() }
job1.join(); job2.join()
}
suspend fun task1() {
delay(1000)
println("task1 complete")
}
suspend fun task2() {
delay(2000)
println("task2 complete")
}
This code prints out "task1 complete" and "taks2 complete" since cancellation is not delivered.
Of course I know we can deliver cancellation by:
suspend fun runParallelTasks(coroutineContext: CoroutineContext) {
val job1 = launch(CommonPool + coroutineContext) { task1() }
val job2 = launch(CommonPool + coroutineContext) { task2() }
job1.join(); job2.join()
}
However I think the above approach looks little redundant because we should add coroutineContext parameter into all suspending functions for delivering cancellation.
Would you have a smart solution?
Thanks.
I would change the above code to this:
suspend fun runParallelTasks() {
val ctx = CommonPool + coroutineContext()
val job1 = launch(ctx) { task1() }
val job2 = launch(ctx) { task2() }
job1.join(); job2.join()
}
Where coroutineContext() function is defined like this:
suspend fun coroutineContext(): CoroutineContext = suspendCoroutineOrReturn { cont -> cont.context }
It is going to be added to stdlib in the future. See https://youtrack.jetbrains.com/issue/KT-17609
Thanks @elizarov, it helps me a lot!
suspendCoroutineOrReturn is a intrinsics function so I use
suspend fun coroutineContext(): CoroutineContext = suspendCoroutine { it.resume(it.context) }
as workaround and it does work well.
That works too, though it is slightly less efficient. You can always import intrinsics with import kotlin.coroutines.experimental.intrinsics.*
Most helpful comment
That works too, though it is slightly less efficient. You can always import intrinsics with
import kotlin.coroutines.experimental.intrinsics.*