Hi, can someone please explain why following takes...
# coroutines
m
Hi, can someone please explain why following takes 5000ms instead of 200ms? And how do I make the
withContext
call cancellable by timeout?
Copy code
fun main() = runBlocking<Unit> {
    withTimeout(200) {
        withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
            Thread.sleep(5000)
        }
    }
}
z
Because coroutine cancellation is cooperative (opt-in) and doesn’t have any effect on actual blocking calls by default (i.e. sleep). If
sleep
here represents an actual blocking call (like an
InputStream
read), you can use
runInterrupting
to interrupt the blocked thread when the coroutine is cancelled.
👍 1
i
delay(5000)
is the coroutine equivalent to
Thread.sleep(5000)
that plays nicely with cancellation, etc.
👆 4
👎 1
m
@Zach Klippenstein (he/him) [MOD] thank you so much, that's it! Can't believe I have never seen it before
m
I would’ve used
Dispatchers.Default
but thinking about it
IO
actually makes more sense 😄
m
the
Thread.sleep()
call was there as a placeholder for any blocking call (database query in my particular case)
👍 1
g
If your blocking call supports thread interruption, you can use this to integrate it with coroutine cancellation https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/run-interruptible.html But it works only if it supported by blocking code (which not very common, unfortunately), but it should fix cancellation for your Thread.sleep example above (just because sleep supports interruption)
👍 1
s
I had the exact same case a week ago. Since I could not rely on cancellation I had to "detach" the blocking call from the job like:
Copy code
fun main() = runBlocking<Unit> {
    withTimeout(200) {
        GlobalScope.async(<http://Dispatchers.IO|Dispatchers.IO>) {
            Thread.sleep(5000)
        }.await()
    }
}
In effect "leaking" the threads.. and just letting them fail or complete in the background.