Java线程亲和性

69

有没有人知道如何锁定Java进程中的单个线程到特定的CPU核心上(在Linux系统下)?我已经在C语言中实现了这一功能,但无法找到Java的实现方法。我的直觉是需要进行JNI调用,但我希望这里的某个人可能有一些见解或以前做过。

谢谢!


1
请看我对Hassan评论的回答。有些线程非常I/O密集,而其他线程则是CPU密集型的。如果我要将I/O中断屏蔽到特定的核心,则希望I/O密集型线程位于同一插座上的核心上,并且希望将CPU密集型线程从I/O中屏蔽。 - Dave
46
像这种“质疑问题”的情况一如既往地存在:SO不关心“为什么”,而是关心“如何”。CPU亲和力是有原因的,Linux和Windows都有工具来设置进程的CPU亲和性。OP的问题非常合理,只想知道“如何”,而不是“为什么”。 - SyntaxT3rr0r
6
我认为在 Stack Overflow 上不会禁止提出“为什么”的问题,而且由于 Java 通常不是与并发性能优化相关的编程语言,所以进行一次合理性检查是有必要的。 - gimpf
现在我需要这个问题的答案,以便实施NUMA优化。 - Tim Cooper
我喜欢这些“你为什么想要做这个”的问题?如果一个认真的工程师问了什么,请考虑可能需要认真回答。 - Martin Kersten
5个回答

49

在纯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
+1:我已经将这个功能转化为一个库,它使用JNI或JNA取决于可用性。它还具有低延迟计时器,并支持使用PAUSE汇编指令进行忙等待。https://github.com/peter-lawrey/Java-Thread-Affinity - Peter Lawrey
2
最好通过此方式记录错误 https://github.com/peter-lawrey/Java-Thread-Affinity/issues,以免被遗忘。 - Peter Lawrey
两个链接都无法访问。这个问题仍然相关。能否请您更新一下链接? - Manu Manjunath
不知道如何将博客带回来 :) 但是这个想法非常简单,你只需要通过JNA/JNI进行适当的系统调用。详细信息可以在3或4个链接中找到。 - BegemoT
@PeterLawrey - 我发现了这个...再次感谢您在另一个线程上的帮助:https://dev59.com/iWYr5IYBdhLWcg3wNHmh#13866186?noredirect=1#comment53518747_13866186 - Xofo
显示剩余3条评论

9

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

  1. "jstack -l "
  2. 获取结果,找到我想要手动锁定到核心的线程的“nid”。
  3. 将这些线程绑定到特定的核心上。

2
出于兴趣,我认为taskset只适用于进程而不是单个线程。如何对线程执行此操作的语法是什么? - Matt
Java代码不是由处理器执行的机器码,而是由另一个程序(JVM)扫描和解释的数据。 JVM可以以完全任意的方式实现线程。 即使JVM生成其他进程来执行线程,也不能保证当线程被丢弃时它会被同一进程重新接管。 即使它这样做了,也不能保证将来的JVM实现会以相同的方式行事。 - Terrible Tadpole


0
在我看来,除非使用本地调用,否则这是不可能的。JVM 应该是平台无关的,任何为了实现这一点而进行的系统调用都不会产生可移植的代码。

7
我不担心可移植性。 - Dave
5
如果只有在发现Java程序运行在支持该系统调用的操作系统上时才进行系统调用,那怎么办?这样代码仍然是可移植的,但在其他操作系统上不会设置任何CPU亲和性。这是一件让人发笑的事情:当你使用JNI或Runtime.exec()时,有些人会大喊“非可移植代码”。我有一些程序同时使用两者,在Linux、Windows和OS X上都能正常运行。 - SyntaxT3rr0r
关键不在于使用或不使用本地调用,而在于平台是否“开箱即用”支持此功能。@questzen 正确指出,JVM 不会抽象访问此功能,因为它并不是非常平台中立的。您可能能够找到第三方库来完成这项工作。 - PSpeed

0

这在纯Java中是不可能的。

您可以使用线程池来限制用于不同类型工作的线程(因此也限制了核心数),但无法指定要使用的核心。

甚至有可能您的Java运行时不支持您的操作系统或硬件的本机线程。在这种情况下,将使用绿色线程,整个JVM只能使用一个核心。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接