I am learning Kotlin by reading the <Programming Kotlin book>. In the section about coroutine cancel...
m
I am learning Kotlin by reading the Programming Kotlin book. In the section about coroutine cancellations (page 319-320), it suggest to wrap long running blocking code with
async { doStuff() }.await()
to make the coroutine cancellable (see
code/async/cancelandsuspension.kts
in https://media.pragprog.com/titles/vskotlin/code/vskotlin-code.zip). Is that really a good advice? It seems like the long running blocking code is not cancelled, it is simply detached from the parent coroutine and will continue to run to completion in backround, and will block the completion of the surrounding
runBlocking
.
Copy code
fun getResponse(ms: Int): String {
    val s = URL("<http://httpstat.us/200?sleep=$ms>").readText()
    println("${LocalTime.now()} Got: $s")
    return s
}

suspend fun fetchResponse() = coroutineScope {
    try {
        println(async { getResponse(4000) }.await())
    } catch (ex: CancellationException) {
        println("${LocalTime.now()} fetchResponse: ${ex.message}")
    }
}

fun main() {
    println("${LocalTime.now()} before runBlocking")
    runBlocking {
        val job = launch(Dispatchers.Default) {
            launch { fetchResponse() }
        }

        println("${LocalTime.now()} Let it run...")
        delay(2000)
        println("${LocalTime.now()} OK, that's enough, cancel")
        job.cancel()
        println("${LocalTime.now()} end of runBlocking")
    }
    println("${LocalTime.now()} after runBlocking")
}
u
Nothing much to add. Cancelation is cooperative and no async/await will magically make your long running code cancelable. Wether it is good advise depends on your circumstances. Sometimes the top goal is to avoid successful completion. i.e. on android you don’t want the response from your readtext to be forwarded to a dead activity. What’s missing from my pov is a word of warning that cancelation in that case can not actually abort the blocking code.
e
runInterruptible
can interrupt typical Java blocking code
m
Not my example with reading from
java.net.URL
it seems.
e
it translates cancellations into
Thread.interrupt()
which stops
Thread.sleep()
, lock acquisition, and some I/O. if it doesn't stop
URL.getText()
then there's no way of stopping it in Java either
perhaps you could try `ExecutorService.submit().await()`; that should at least abort the await even if it can't stop the operation
m
Not sure what you mean with aborting the await 🤔 Even the original example I posted aborts the await.