https://kotlinlang.org logo
Title
f

feroz_baig

07/26/2017, 8:11 AM
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

diesieben07

07/26/2017, 8:12 AM
Because it never suspends. It just keeps looping, so there is no way to cancel it.
f

feroz_baig

07/26/2017, 8:13 AM
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

diesieben07

07/26/2017, 8:13 AM
Yes, and it should be canceled here.
f

feroz_baig

07/26/2017, 8:14 AM
It gets cancelled after
job.cancel()
Why did it not happen in the first case?
d

diesieben07

07/26/2017, 8:15 AM
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

feroz_baig

07/26/2017, 8:16 AM
Thanks!
p

pilgr

07/26/2017, 8:25 AM
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

voddan

07/26/2017, 8:55 AM
@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

kingsley

07/26/2017, 9:15 AM
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

uhe

07/26/2017, 9:18 AM
don't we have
yield()
for this?
p

pilgr

07/26/2017, 9:22 AM
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

kingsley

07/26/2017, 9:35 AM
Ah. Yes.
yield
. For a moment, I thought that was only available to
generateSequence
2