【问题标题】:Java thread affinityJava 线程亲和性
【发布时间】:2011-01-15 08:19:55
【问题描述】:

是否有人知道将 Java 进程中的单个线程锁定到特定 CPU 内核(在 Linux 上)的方法?我已经在 C 中完成了此操作,但在 Java 中找不到如何执行此操作。我的直觉是这将需要一个 JNI 调用,但我希望这里的某个人可能有一些见解或可能以前做过。

谢谢!

【问题讨论】:

  • 在下面查看我对 Hassan 评论的回答。一些线程是非常 I/O 密集型的,而另一些则是 CPU 密集型的。如果我要屏蔽对特定内核的 I/O 中断,我希望 I/O 密集型线程位于同一插槽上的内核上,并且我希望屏蔽 CPU 密集型线程免受 I/O 的影响.
  • @gimpf:一如既往地使用这种类型的“问题提问”:所以不是关于“为什么”,而是关于“如何”。 CPU 亲和性的存在是有原因的,Linux 和 Windows 下都有实用程序来设置进程的 CPU 亲和性是有原因的。 OP 的问题是一个完全有效的问题,它不需要“为什么”而是“如何”。
  • @WizardOfOdds:我怀疑“为什么”在 SO 上是被禁止的,而且由于 Java 通常不是用于并发相关性能调整的第一种编程语言,我认为健全性检查是有效的。跨度>
  • 现在我需要这个问题的答案才能实现 NUMA 优化。
  • 我喜欢这些“你为什么要做这个问题?”如果一位认真的工程师提出问题,请考虑一下这可能是需要认真回答的问题。

标签: java multithreading scheduling setthreadaffinitymask


【解决方案1】:

IMO,除非您使用本机调用,否则这不会是可能的。 JVM 应该是独立于平台的,为实现这一点所做的任何系统调用都不会产生可移植的代码。

【讨论】:

  • 我不关心便携性。
  • @questzen:如果仅在发现 Java 程序在支持所述调用的操作系统上运行时才进行系统调用怎么办?该代码仍然是可移植的,但根本不会在其他操作系统上设置任何 CPU 亲和性。这是一件总是让我崩溃的事情:一旦你执行一些 JNI 或一些 Runtime.exec(),人们就会尖叫“不可移植代码”。我的程序可以同时在 Linux、Windows 和 OS X 上运行。
  • 这不是关于是否使用原生调用,而是关于平台是否支持这种“开箱即用”。 @questzen 是正确的,JVM 不会抽象对此的访问,因为它不是平台中立的。您也许可以找到可以做到这一点的第三方库。
【解决方案2】:

这是不可能的(至少对于普通 Java)。

您可以使用thread pools 来限制用于不同类型工作的线程(以及内核)数量,但无法指定要使用的内核。

您的 Java 运行时甚至有(很小的)可能性不支持您的操作系统或硬件的本机线程。在这种情况下,green threads 被使用,整个 JVM 将只使用一个内核。

【讨论】:

    【解决方案3】:

    我知道这已经有一段时间了,但是如果有人遇到这个线程,这就是我解决这个问题的方法。我编写了一个脚本,它会执行以下操作:

    1. “jstack -l”
    2. 获取结果,找到我想要手动锁定到核心的线程的“nid”。
    3. 任务集那些线程。

    【讨论】:

    • 出于兴趣,我认为任务集仅适用于进程而不是单个线程。对线程执行此操作的语法是什么?
    • Java 代码不是由处理器执行的机器代码,而是由另一个程序(JVM)扫描和解释的数据。 JVM 可以以完全任意的方式实现线程。即使 JVM 产生了额外的进程来执行线程,也不能保证当一个线程被丢弃时,它会被同一个进程再次拾取。即使这样,也不能保证 JVM 的未来实现会以同样的方式运行。
    【解决方案4】:

    你不能在纯 java 中做到这一点。但是如果你真的需要它——你可以使用 JNI 来调用本机代码来完成这项工作。这是开始的地方:

    http://ovatman.blogspot.com/2010/02/using-java-jni-to-set-thread-affinity.html

    http://blog.toadhead.net/index.php/2011/01/22/cputhread-affinity-in-java/

    UPD: 经过一番思考,我决定为此创建自己的类:ThreadAffinity.java 它基于 JNA,而且非常简单——所以,如果你想在生产,也许你应该花一些时间让它更稳定,但是对于基准测试和测试,它可以正常工作。

    UPD 2: 还有一个 library 用于在 java 中处理线程关联。它使用与前面提到的相同的方法,但有另一个接口

    【讨论】:

    • +1 有效!惊人的!请注意我在第一篇博客中留下的评论 - 你需要 #define _GNU_SOURCE 最重要的包含。
    • +1:我已经将此功能变成了一个库,它根据可用的内容使用 JNI 或 JNA。它还具有低延迟计时器,并支持使用 PAUSE asm 指令忙等待。 github.com/peter-lawrey/Java-Thread-Affinity
    • @PeterLawrey 太好了,谢谢! (假设它有效,我尚未验证)。但是,您的库存在一些问题(主要是文档和错误);我该如何与您联系?
    • 最好以这种方式记录错误github.com/peter-lawrey/Java-Thread-Affinity/issues,这样它们就不会被遗忘
    • 这确实是最好的方法,虽然我下面的方法也有效。
    【解决方案5】:
    猜你喜欢
    • 2017-12-06
    • 2012-11-07
    • 1970-01-01
    • 2013-04-25
    • 2019-08-09
    • 1970-01-01
    相关资源
    最近更新 更多