Kotlin coruntines在启动和回调时不会执行

Kotlin coruntines在启动和回调时不会执行,kotlin,kotlin-coroutines,Kotlin,Kotlin Coroutines,我以为我对Kotlin的协同程序已经足够熟悉了,直到我得到了这个代码 1到8都是打印的,除了2: import kotlinx.coroutines.* import java.lang.Runnable import java.lang.Thread.sleep import kotlin.concurrent.thread fun main() { runBlocking { Client.createAccount() delay(1000)

我以为我对Kotlin的协同程序已经足够熟悉了,直到我得到了这个代码

1到8都是打印的,除了2:

import kotlinx.coroutines.*
import java.lang.Runnable
import java.lang.Thread.sleep
import kotlin.concurrent.thread

fun main() {
    runBlocking {
        Client.createAccount()
        delay(1000)
    }
}

object Client: CoroutineScope {
    override val coroutineContext = newSingleThreadContext("Client")

    fun createAccount() = launch {
        Client2.init(Runnable {
            println('1')
            launch {
                println('2')
            }
            ok()
            ok2()
        })

        println('7')
        launch {
            println('8')
        }
    }

    fun ok() {
        println('3')
        launch {
            println('4')
        }
    }

    fun ok2() = launch {
        println('5')
        launch {
            println('6')
        }
    }
}

object Client2 {

    fun init(runnable: Runnable) = thread {
        sleep(100)
        runnable.run()
    }
}
结果是:

7
8
1
3
4
5
6
回调中的协程将永远不会被调用。为什么? 如果我删除
createAccount()
中的
launch
,1到8都将被打印出来。
另外,如果我使用
GlobalScope.launch{println('2')}
而不是
launch{println('2')}
,我还可以打印2。

launch在处理程序中发布一个Runnable,因此它的代码不会立即执行。 launch(Dispatchers.Main、CoroutineStart.UNDISPATCHED)将立即在当前线程中执行其lambda表达式

将调度程序更改为当前正在使用的调度程序 将午餐从线内改为

launch (coroutineContext, CoroutineStart.UNDISPATCHED)

输出:

7
8
1
2
3
4
5
6

原因是匿名类将其包装作用域用作父类

当父作业
createAccount()
启动完成时,
Runnable{}
中的
launch{println('2')}
将被取消

因此,无法调用它,因为它将在
启动{println('8')}
后立即取消

因此,如果您像下面这样更改
客户端
,它将正确打印“2”

object Client: CoroutineScope {
    override val coroutineContext = Dispatchers.Main

    fun createAccount() = launch {
        Client2.init(Run())

        println("7")
        launch {
            println("8")
        }
    }

    fun ok() {
        println("3")
        launch {
            println("4")
        }
    }

    fun ok2() = launch {
        println("5")
        launch {
            println("6")
        }
    }

    class Run: Runnable {
        override fun run() {
            println("1")
            launch {
                println("2")
            }
            ok()
            ok2()
        }
    }
}

你真的解决了我的问题!您能给我一些指南或文档来了解包装器作用域的行为吗?非常感谢。我不确定。。。但匿名内部类最初在jvm中具有包装依赖性,而不是通过协同路由。如果我错了,请让我知道。(+我通过转换成kotlin字节码解决了你的问题)谢谢你给我这个解决方案,它工作得很好!我还找到了CoroutineStart.ATOMIC,但我不明白为什么会打印4和6,而不会打印2。Choim回答我的疑问,也许你可以看看
object Client: CoroutineScope {
    override val coroutineContext = Dispatchers.Main

    fun createAccount() = launch {
        Client2.init(Run())

        println("7")
        launch {
            println("8")
        }
    }

    fun ok() {
        println("3")
        launch {
            println("4")
        }
    }

    fun ok2() = launch {
        println("5")
        launch {
            println("6")
        }
    }

    class Run: Runnable {
        override fun run() {
            println("1")
            launch {
                println("2")
            }
            ok()
            ok2()
        }
    }
}