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