为了澄清术语,yield 是线程放弃其时间片的时间。我感兴趣的平台是 POSIX 线程,但我认为这个问题很笼统。
假设我有消费者/生产者模式。如果我想限制消费者或生产者,哪个更好用,睡眠还是产量?我最感兴趣的是使用这两种功能的效率。
为了澄清术语,yield 是线程放弃其时间片的时间。我感兴趣的平台是 POSIX 线程,但我认为这个问题很笼统。
假设我有消费者/生产者模式。如果我想限制消费者或生产者,哪个更好用,睡眠还是产量?我最感兴趣的是使用这两种功能的效率。
编写生产者/消费者的“正确”方法是让消费者等待生产者的数据。您可以通过使用诸如 Mutex 之类的同步对象来实现此目的。消费者将Wait
使用互斥锁,这会阻止它执行,直到数据可用。反过来,生产者将在数据可用时向互斥体发出信号,这将唤醒消费者线程,以便它可以开始处理。这比sleep
两者都更有效:
也就是说,这是您要求的产量与睡眠的分析。如果由于某种原因等待输出不可行,您可能需要使用这样的方案:
这取决于您收到多少流量 - 如果不断接收和处理数据,您可能会考虑进行收益。然而,在大多数情况下,这将导致一个“忙碌”循环,它花费大部分时间不必要地唤醒线程以检查是否有任何准备就绪。
您可能希望睡眠一小段时间(可能少于一秒,使用usleep
),或者甚至更好地使用诸如互斥锁之类的同步对象来表示数据可用。
sleep 和 yield 是不一样的。当调用 sleep 时,进程/线程在给定的时间内将 CPU 分配给另一个进程/线程。
yield 将 CPU 让给另一个线程,但如果没有其他线程等待 CPU,则可能会立即返回。
因此,如果您想节流,例如在定期流式传输数据时,那么 sleep 或 nanosleep 是要使用的功能。
如果需要生产者/消费者之间的同步,则应使用互斥锁/条件等待。
睡眠而不是屈服的一个很好的理由是在特定的关键部分有太多的争用。例如,假设您尝试获取两个锁,并且两个锁都有很多争用。在这里,您可以使用 sleep 来采用指数回退。这将允许每个失败的尝试伪随机地退回以允许其他线程成功。
在这种情况下屈服并没有太大帮助,因为随机退避的前景可能会增加不会发生线程饥饿的可能性。
编辑:虽然我知道这不一定是特定于 java 的。Java 的实现Thread.sleep(0)
具有与 At that point 相同的效果,Thread.yield()
它更多的是风格问题。
在 java 中,一些 JVM 实现将 Thread.yield() 视为无操作,这意味着它可能没有任何效果。调用 Thread.sleep() 并不一定意味着调度程序应该将 CPU 让给另一个线程;这也取决于实现。它可能会上下文切换到另一个正在等待的线程,也可能不会为了分摊与上下文切换相关的成本。