Search code examples
kotlinkotlinx.coroutines

How to launch a Kotlin coroutine in a `suspend fun` that uses the current parent Scope?


How can I launch a coroutine from a suspend function and have it use the current Scope? (so that the Scope doesn't end until the launched coroutine also ends)

I'd like to write something like the following –

import kotlinx.coroutines.*

fun main() = runBlocking { // this: CoroutineScope
    go()
}

suspend fun go() {
    launch {
        println("go!")
    }
}

But this has a syntax error: "Unresolved Reference: launch". It seems launch must be run in one of the following ways –

GlobalScope.launch {
    println("Go!")
}

Or

runBlocking {
    launch {
        println("Go!")
    }
}

Or

withContext(Dispatchers.Default) {
    launch {
        println("Go!")
    }
}

Or

coroutineScope {
    launch {
        println("Go!")
    }
}

None of these alternatives does what I need. Either the code "blocks" instead of "spawning", or it spawns but the parent scope won't wait for its completion before the parent scope itself ends.

I need it to "spawn" (launch) in the current parent coroutine scope, and that parent scope should wait for the spawned coroutine to finish before it ends itself.

I expected that a simple launch inside a suspend fun would be valid and use its parent scope.

I'm using Kotlin 1.3 and cotlinx-coroutines-core:1.0.1.


Solution

  • You should make the function go an extension function of CoroutineScope:

    fun main() = runBlocking {
        go()
        go()
        go()
        println("End")
    }
    
    fun CoroutineScope.go() = launch {
        println("go!")
    }
    

    Read this article to understand why it is not a good idea to start in a suspend functions other coroutines without creating a new coroutineScope{}.

    The convention is: In a suspend functions call other suspend functions and create a new CoroutineScope, if you need to start parallel coroutines. The result is, that the coroutine will only return, when all newly started coroutines have finished (structured concurrency).

    On the other side, if you need to start new coroutines without knowing the scope, You create an extensions function of CoroutineScope, which itself it not suspendable. Now the caller can decide which scope should be used.