我以为我对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
回调中的协程将永远不会被调用。为什么?
如果我删除了launch
中的createAccount()
,则1至8将全部打印出来。
另外,如果我使用GlobalScope.launch { println('2') }
代替launch { println('2') }
,我也可以打印出2。
答案 0 :(得分:2)
原因是匿名类将其包装范围用作父类。
完成启动的父作业launch { println('2') }
后,Runnable { }
中的 createAccount()
将被取消。
因此,它无法被调用,因为它将在launch { println('8') }
之后立即被取消。
因此,如果您像下面那样更改Client
,它将正确打印'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()
}
}
}
答案 1 :(得分:0)
launch在处理程序中发布一个Runnable,因此它的代码执行不是立即的。 launch(Dispatchers.Main,CoroutineStart.UNDISPATCHED)将立即在当前线程中执行其lambda表达式。
将调度程序更改为当前使用的调度程序 将午餐从线程内更改为
launch (coroutineContext, CoroutineStart.UNDISPATCHED)
。
fun createAccount() = launch {
Client2.init(Runnable {
println('1')
launch (coroutineContext, CoroutineStart.UNDISPATCHED){
println('2')
}
ok()
ok2()
})
println('7')
launch {
println('8')
}
}
输出:
7
8
1
2
3
4
5
6