https://kotlinlang.org logo
Title
m

Milan Hruban

10/12/2020, 4:17 PM
Hi, can someone please explain why following takes 5000ms instead of 200ms? And how do I make the
withContext
call cancellable by timeout?
fun main() = runBlocking<Unit> {
    withTimeout(200) {
        withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
            Thread.sleep(5000)
        }
    }
}
z

Zach Klippenstein (he/him) [MOD]

10/12/2020, 4:19 PM
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

Ian Lake

10/12/2020, 4:22 PM
delay(5000)
is the coroutine equivalent to
Thread.sleep(5000)
that plays nicely with cancellation, etc.
👆 4
👎 1
m

Milan Hruban

10/12/2020, 4:51 PM
@Zach Klippenstein (he/him) [MOD] thank you so much, that's it! Can't believe I have never seen it before
m

Marc Knaup

10/12/2020, 5:34 PM
I would’ve used
Dispatchers.Default
but thinking about it
IO
actually makes more sense 😄
m

Milan Hruban

10/12/2020, 5:52 PM
the
Thread.sleep()
call was there as a placeholder for any blocking call (database query in my particular case)
👍 1
g

gildor

10/12/2020, 11:56 PM
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

spand

10/13/2020, 7:29 AM
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:
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.