```fun main(args: Array<String>) = runBlocki...
# coroutines
f
Copy code
fun main(args: Array<String>) = runBlocking {
            val job = launch(CommonPool) {
                var nextPrintTime = System.currentTimeMillis()
                var i = 0
                while (i < 10) { // computation loop
                    val currentTime = System.currentTimeMillis()
                    if (currentTime >= nextPrintTime) {
                        println("I'm sleeping ${i++} ...")
                        nextPrintTime += 500L
                    }
                }
            }
            delay(1300L) // delay a bit
            println("main: I'm tired of waiting!")
            job.cancel() // cancels the job
            delay(1300L) // delay a bit to see if it was cancelled....
            println("main: Now I can quit.")
            }
Why is the job not cancelled after calling it explicitly?
d
Because it never suspends. It just keeps looping, so there is no way to cancel it.
f
Copy code
fun main(args: Array<String>) = runBlocking<Unit> {
    val job = launch(CommonPool) {
        repeat(1000) { i ->
            println("I'm sleeping $i ...")
            delay(500L)
        }
    }
    delay(1300L) // delay a bit
    println("main: I'm tired of waiting!")
    job.cancel() // cancels the job
    delay(1300L) // delay a bit to ensure it was cancelled indeed
    println("main: Now I can quit.")
}
Well this suspends
d
Yes, and it should be canceled here.
f
It gets cancelled after
job.cancel()
Why did it not happen in the first case?
d
Because the first time the coroutine does not suspend. It just runs and runs and there is no way for the coroutine machinery to make it stop. If you suspend every once in a while, you will just not get re-scheduled (un-suspended) when you're canceled.
đź‘Ť 1
But there is no way for that to happen if you never suspend.
đź‘Ť 1
f
Thanks!
p
cancellation is cooperative, means you should check if job is cancelled inside your
repeat
lambda https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md#cancellation-is-cooperative
v
@elizarov maybe we need a primitive that would suspend, check for cancelation, then immediately resume. Something like
delay(0)
, but optimized for that scenario. Then it could be inserted into long-running jobs like above
If I am not mistaken, the ReSharper people use a similar technique, checking for user's action periodically while doing background file analyzes
k
I think it will be much better if the implementor designs his code such that it is cooperative. That way, there shouldn’t be a need for any trick.
u
don't we have
yield()
for this?
p
you can also have
launch(CommonPool)
inside the
repeat
. In this case I suppose after calling
job.cancel()
coroutine won’t proceed after latest
delay(500L)
. The drawback is frequent context switching.
the
yield()
is a good catch! it’s mentioned as one of the ways to make computation cancellable but no examples https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md#making-computation-code-cancellable
k
Ah. Yes.
yield
. For a moment, I thought that was only available to
generateSequence
âž• 2