Answers:
轮询是指反复检查资源(任何类型的资源)是否准备就绪。
自旋锁是指您要轮询的资源处于锁定状态。
请注意,轮询还不错。特别是,在轮询时通常准备好数据时,轮询是有效的。轮询仅在您不进行任何操作而不获取任何数据的情况下才是低效的。
另一方面,如果有太多数据以至于不断被中断,则中断效率很低。如果数据很少到达,以至于您实际上可以在中断之前完成一些有用的工作,它们将非常有效。
我可以从我的经验中给你一个真实的例子:15年前,我设置了我的电子邮件程序,每次收到新电子邮件时都会打扰我。每周发生一两次。经常检查我的收件箱会浪费大量时间。
如今,我已关闭所有通知。我知道,每当我查看收件箱时,都会有新的电子邮件。轮询现在效率更高。
自旋锁在以下情况下非常有效:a)锁被锁的可能性很低,b)如果锁被锁了,那么锁将只保留一小段时间。换句话说:对于大多数无竞争的细粒度锁,它是有效的,但对于高度竞争的粗粒度锁,则效率不高。
(当然,自旋锁仅在存在真正的并行性时才起作用,否则其他线程将没有机会释放该锁。我想这很明显,但是无论如何我都想声明它。)
atomically_do { while (lock.is_locked?); lock.acquire! }
)如果它屈服,那不是纯粹的循环,因此从那个纯粹的观点来看不是自旋锁:-D但是,当然,与其他类型的锁或对柏拉图式理想的放松/增添的杂交在现实世界中是完全合理的。
不同之处在于(希望)自旋锁仅在适当的情况下使用,并且在这些情况下非常有效。
如果期望资源仅在很短的时间内被锁定(例如,仅用于更新变量的锁定),则可以使用自旋锁。自旋锁以最大速度轮询该锁,但希望少于一微秒。普通互斥锁将需要在OS上调用。如果仅将锁保持一小段时间,那么自旋锁仅占用很少的CPU时间,而OS调用将花费更长的时间。但是,如果这种期望是错误的,则自旋锁效率很低-一个CPU将占用100%的CPU时间,而普通互斥锁仅花费进入操作系统并返回的时间。
有时两者结合在一起。您将运行自旋锁一小段时间,如果自旋锁不起作用,则切换到其他策略。
过多的轮询是您不应该执行的操作,因为它浪费了系统资源。因此,如果不浪费系统资源,则轮询是可以的。
例如,在实际工作仅导致2%的负载的情况下,过多的轮询将使CPU负载达到100%。
轮询除了可以用于其他用途while(!ready)
。例如,这意味着定期检查用户是否按下了按键。一个理智的实现最多每15毫秒检查一次,因此,它是每2000万个时钟周期一次的检查。这种轮询非常好,因为它不会浪费系统资源。
自旋锁不是特殊情况。如果我们有一个SpinLock,并且一个线程进入了锁,而另一个线程必须等待,则当且仅当正在等待的线程浪费了系统资源时,SpinLock是错误的选择。当且仅当等待线程必须等待大量时间才能获取锁时,才会浪费系统资源。
因此,正是出于您所说的原因,使用SpinLock保护需要几千个时钟周期或更长时间才能再次解锁的任何东西(例如,即时编译和执行一段javascript)是不好的。但是使用SpinLock保护快速完成的操作(例如访问正确实现的哈希映射)很好,因为等待线程只会旋转2到3次,因此不会浪费系统资源。