web-dev-qa-db-ja.com

現在の親スコープを使用する「サスペンドファン」でKotlinコルーチンを起動する方法は?

サスペンド関数からコルーチンを起動し、現在のスコープを使用させるにはどうすればよいですか? (起動されたコルーチンも終了するまでスコープが終了しないように)

私は次のようなものを書きたいです-

import kotlinx.coroutines.*

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

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

ただし、これには「未解決の参照:起動」という構文エラーがあります。 launchは、次のいずれかの方法で実行する必要があるようです–

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

または

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

または

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

または

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

これらの選択肢のどれも私が必要としていることをしません。コードは「スポーン」ではなく「ブロック」するか、スポーンしても親スコープ自体が終了する前に親スコープが完了するのを待機しません。

現在の親コルーチンスコープで「スポーン」(起動)する必要があります。その親スコープは、スポーンしたコルーチンが終了する前に、コルーチンが終了するのを待つ必要があります。

suspend fun内の単純なlaunchが有効であり、その親スコープを使用すると予想していました。

Kotlin 1.3cotlinx-coroutines-core:1.0.1を使用しています。

11

関数goCoroutineScopeの拡張関数にする必要があります。

fun main() = runBlocking {
    go()
    go()
    go()
    println("End")
}

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

これを読んで 記事 新しいcoroutineScope{}を作成せずにsuspend関数、他のコルーチンから始めるのがなぜ良い考えではないのかを理解してください。

規則は次のとおりです。並列コルーチンを開始する必要がある場合は、suspend関数で他のsuspend関数を呼び出し、新しいCoroutineScopeを作成します。その結果、新しく開始されたすべてのコルーチンが終了したときにのみ、コルーチンが返されます(構造化された並行性)。

一方、スコープを知らずに新しいコルーチンを開始する必要がある場合は、CoroutineScopeの拡張関数を作成しますが、それ自体はsuspendableではありません。これで、呼び出し元は使用するスコープを決定できます。

5
Rene

私はwith(CoroutineScope(coroutineContext)という解決策を見つけたと思います。次の例はこれを示しています–

import kotlinx.coroutines.*

fun main() = runBlocking {
    go()
    go()
    go()
    println("End")
}

suspend fun go() {
//  GlobalScope.launch {                     // spawns, but doesn't use parent scope
//  runBlocking {                            // blocks
//  withContext(Dispatchers.Default) {       // blocks
//  coroutineScope {                         // blocks
    with(CoroutineScope(coroutineContext)) { // spawns and uses parent scope!
        launch {
            delay(2000L)
            println("Go!")
        }
    }
}

ただし、ルネは上記のはるかに優れたソリューションを投稿しました。

1