我不确定yield
函数的用途是什么。
您能检查一下我有这个例子吗?
尽管如此,我仍在跟踪示例here。
代码如下:
val job = launch {
val child = launch {
try {
delay(Long.MAX_VALUE)
} finally {
println("Child is cancelled")
}
}
yield() //why do i need this ???????
println("Cancelling child")
child.cancel()
child.join()
yield()
println("Parent is not cancelled")
}
job.join()
当我注释掉第一笔收益时,我得到以下结果:
取消孩子
父级未取消
但是如果我保持产量不变,我会得到:
取消孩子
孩子被取消
父级未取消
在这里使用yield
是什么意思?
答案 0 :(得分:3)
在您的示例中,yield()在父作业内部被调用。它对您的父母说:“您的工作更多,请稍等,我将让其他任务工作一段时间,一段时间后,我将让您继续工作”。
因此父作业正在等待。 童工工作一段时间。 一段时间后,父作业通过yield()之后的下一行,并取消子作业。
如果在示例中未使用yield(),则父作业立即取消子作业。
让我用不同的示例来说明产量,该示例以更清晰的方式显示了产量。 2个作业在队列中等待线程等待它们工作。当您调用yield时,线程会进入队列并看到其他作业正在等待,这样它就可以使其他作业正常工作。
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.yield
fun main() = runBlocking {
val job1 = launch {
repeat(10) {
delay(1000)
println("$it. step done in job 1 ")
yield()
}
}
val job2 = launch {
repeat(10) {
delay(1000)
println("$it. step done in job 2 ")
yield()
}
}
job1.join()
job2.join()
println("done")
}
输出:
0. step done in job 1
0. step done in job 2
1. step done in job 1
1. step done in job 2
2. step done in job 1
2. step done in job 2
3. step done in job 1
3. step done in job 2
4. step done in job 1
4. step done in job 2
5. step done in job 1
5. step done in job 2
6. step done in job 1
6. step done in job 2
7. step done in job 1
7. step done in job 2
8. step done in job 1
8. step done in job 2
9. step done in job 1
9. step done in job 2
done
答案 1 :(得分:2)
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/yield.html
产生当前协程调度程序的线程(或线程池) 到其他协程运行。如果协程调度员没有 它自己的线程池(如Dispatchers.Unconfined),然后此函数 什么都不做,但是检查协程作业是否完成。这个 暂停功能是可以取消的。如果当前的工作 当此暂停功能启用时,协程将被取消或完成 调用,或者在此函数等待分派时恢复 带有CancellationException。
它至少可以完成几件事
答案 2 :(得分:2)
我对协程也不陌生,我对协程流程的理解是launch
中的代码将像最后一次执行一样执行,就在退出main函数之前。为了优先考虑,我们使用-delay, yield, join
。在此示例中,我们可以将yield
更改为delay
,并将得到相同的结果。
流程:
应用跳过job = launch
到job.join()
,
了解未来的代码正在等待工作=启动'将
完成
应用跳过child= launch
进入yield()
或
我们可以使用delay(10)
并了解将来的代码不是
很重要,并且可以追溯到开始,所以child= launch
进入delay(Long.MAX_VALUE)
这是一个陷阱
应用程序进入println("Cancelling child")
,然后到达child.cancel()
和child.join()
,后者是流触发。在这种情况下,我们可以用yield or join
代替它。在该触发器应用程序之后,了解到child = launch
被取消,但是finally
语句未执行,并执行println("Child is cancelled")
。
执行yield()
(我发现它没用),然后执行println("Parent is not cancelled")
。
您的问题--- yield()//为什么我需要这个?
因为如果没有yield
,应用程序将不会回到child= launch
,也不会进入try
块内,并且在代码到达child.join()之后,finally
与{由于之前没有触发println("Child is cancelled")
块,因此不会执行{1}}。
我建议在调试模式下运行此代码,并在每行上设置断点,并在Intellij中使用“ F9”来了解流程,并尝试在运动场中使用Alex Yu代码并更改try
答案 3 :(得分:1)
@Vasile的answer与问题最相关,@ Yuri Schimke接受的答案只是一般性信息,实际上并未回答问题。
为了说明第一个yield
的需要,让我们通过添加两个“ *正在运行”语句来稍微更改代码:
val job = launch {
val child = launch {
try {
println("Child is running")
delay(Long.MAX_VALUE)
} finally {
println("Child is cancelled")
}
}
yield() // without this, child job doesn't get executed
println("Cancelling child")
child.cancel()
child.join()
yield()
println("Parent is not cancelled")
}
println("Parent is running")
job.join()
输出:
Parent is running
Child is running
Cancelling child
Child is cancelled
Parent is not cancelled
在没有第一个yield
的情况下,由于子作业没有运行的机会,因此不会打印“ 子正在运行”。 delay
暂停子级执行并恢复父级执行。 cancel
中断delay
,并将执行移至finally
块中。 join
和第二个yield
并没有实际效果,但是通过在子作业上调用join
,我们绝对确保仅在子项完成/取消后才执行以下任何代码
答案 4 :(得分:0)
经过一些研究,我发现yield实际上来自java,而术语yield a thread是我不理解的。
本质上:yield()基本上意味着线程没有做任何重要的事情,如果需要运行其他线程,则可以运行它们。 (我更喜欢使用Alex Yu提到的join)。基本上,如果我们要可视化yield的执行情况...。无论您调用yield的线程将被推送到消息传递队列的后面,然后具有相同优先级的其他线程将在该线程之前执行。所以就像去俱乐部后面。
答案 5 :(得分:-1)
suspend fun yield(): Unit (source)
Yields当前coroutine
调度程序的线程(或线程池)到其他coroutine
的运行(如果可能)。
该暂停功能是可以取消的。如果在调用此挂起功能时或在此函数等待分派时当前coroutine
的作业被取消或完成,它将以CancellationException
恢复。
注意: 此功能始终会检查取消,即使它没有挂起。