Thread.onSpinWait() 期间 CPU 使用率为 100%

-2 java concurrency performance multithreading wait

我正在为我的加密交易机器人编写一个回测原始数据收集器,但我遇到了一个奇怪的优化问题。

我在 Executors.newCachedThreadPool() 中经常有 30 个 runnables 运行从 API 获取请求。由于 API 的请求限制为每分钟 1200 次,因此我的可运行文件中有以下代码:

    while (minuteRequests.get() >= 1170) {
        Thread.onSpinWait();
    }
Run Code Online (Sandbox Code Playgroud)

是的,minuteRequests 是一个 AtomicInteger,所以我没有遇到任何问题。

一切正常,问题是即使我使用推荐的忙等待 onSpinWait 方法,当等待开始时,我的 CPU 使用率从 24% 左右上升到 100%。作为参考,我在 3900X(24 线程)上运行它。

关于如何更好地处理这种情况的任何建议?

Ste*_*n C 6

我的建议是不要做忙等待可言


的javadocThread.onSpinWait这样说:

表示调用者暂时无法继续,直到其他活动的一个或多个动作发生。通过在自旋等待循环构造的每次迭代中调用此方法,调用线程向运行时指示它正在忙等待。运行时可能会采取措施来提高调用自旋等待循环构造的性能

请注意突出显示的部分使用单词may而不是will。这意味着它也可能什么都不做。此外,“提高性能”并不意味着您的代码在客观上是高效的。

javadoc 还暗示改进可能取决于硬件。

简而言之,这是正确的使用方式onSpinwait……但是您对它期望过高。它不会使您的忙等待代码高效。


那么我会建议你实际做什么?

我建议您将其替换AtomicIntegerSemaphore( javadoc )。此特定循环将替换为以下内容:

semaphore.acquire();
Run Code Online (Sandbox Code Playgroud)

这会阻塞1,直到 1 个“许可”可用并获得它。有关信号量如何工作的说明,请参阅类 javadocs。

注意:由于您没有向我们展示您的速率限制的完整实现,目前尚不清楚您当前的方法实际上是如何工作的。因此,我无法确切地告诉您如何替换AtomicIntegerwith Semaphore


1 - 被阻塞的线程被“停放”,直到其他线程释放许可。当它停放时,线程不会运行并且不与 CPU 内核相关联。内核要么处于空闲状态(通常处于低功耗状态),要么被分配给其他线程。这通常由操作系统的线程调度程序处理。当另一个线程释放许可时,该Semaphore.release方法将告诉操作系统解除在中阻塞的线程之一acquire

  • @PressFToMakeGames 停车和等待之间没有区别。您的循环只是在线程“可运行”时执行的代码,而不是阻塞且不等待。 (2认同)