Igor Kustov
Igor Kustov

Reputation: 797

Difference between withContext and suspendCancellableCoroutine

I'm new to coroutines

This is a popular example:

suspend fun findBigPrime(): BigInteger =
    withContext(Dispatchers.IO) {
        BigInteger.probablePrime(4096, Random()))
    }

However, it could be written as well as:

suspend fun findBigPrime(): BigInteger =
    suspendCancellableCoroutine {
        it.resume(BigInteger.probablePrime(4096, Random()))
    }

What's the real difference?

Upvotes: 2

Views: 2068

Answers (2)

Marko Topolnik
Marko Topolnik

Reputation: 200166

What's the real difference?

There's hardly any relationship, in fact.

suspendCancellableCoroutine {
    it.resume(BigInteger.probablePrime(4096, Random()))
}

This does nothing but add useless overhead above the simple direct call

BigInteger.probablePrime(4096, Random())

If you resume the continuation while still inside the suspendCancellableCoroutine block, the coroutine doesn't suspend at all.

withContext(Dispatchers.IO) {
    BigInteger.probablePrime(4096, Random()))
}

This suspends the coroutine and launches an internal coroutine on another thread. When the internal coroutine completes, it resumes the current one with the result.

Upvotes: 3

Animesh Sahu
Animesh Sahu

Reputation: 8106

Use of suspendCancellableCoroutine here is a "BIG NO".

withContext changes the context on which the block (coroutine) will run, here the Dispatcher which dispatches the coroutine to a specified thread is overridden. While the suspendCoroutine/suspendCancellableCoroutine are used for wrapping asynchronous callbacks which does not block the thread instead they run on thread of their own.

Usually work on the suspendCoroutine/suspendCancellableCoroutine is non-blocking and gets completed quite quickly and the continuation is resumed after the work has completed in a non-blocking way maybe in other thread or so.

If you put blocking code in there the concept of coroutine is lost, it will just going to block the thread it is running on.

Use of suspendCoroutine/suspendCancellableCoroutine:

// This function immediately creates and starts thread and returns
fun findBigPrimeInNewThread(after: (BigInteger) -> Unit) {
    Thread {
        BigInteger.probablePrime(4096, Random()).also(after)
    }
}

// This just wraps the async function so that when the result is ready resume the coroutine
suspend fun findBigPrime(): BigInteger =
    suspendCancellableCoroutine { cont ->
        findBigPrimeInNewThread {
            cont.resume(it)
        }
    }

Upvotes: 1

Related Questions