我该如何确定Java线程正在运行哪个核心?

14
我想实现一个CoreLocal映射,与ThreadLocal类似,但它返回的值是特定于当前线程所在核心的值。
这是因为我想编写代码,从队列中获取作业,但我希望优先处理那些与从队列中获取作业的线程在相同L1缓存中的相关数据。因此,我想为每个核心设置一个队列,而只有当队列为空时,工作线程才会查看其他核心的队列。

3
https://github.com/peter-lawrey/Java-Thread-Affinity - bmargulies
3
听起来你的纳秒非常短缺。 - djechlin
4
你能否保证线程一旦从队列中获取作业后不会被重新调度到另一个核心,使得所有这些机制都变得无效? - JB Nizet
Q==队列!将线程保留在具有热缓存的核心上比纳秒更有价值 (http://webtide.intalio.com/2012/12/avoiding-parallel-slowdown-in-jetty-9/)。我不知道线程可以多频繁地或在什么事件上跳过内核,但你必须假设存在一些亲和力,否则缓存根本无法工作。 - gregw
@gregw 我想知道你是否在CoreLocal方面取得了一些进展,或者最终是如何解决的。 - maaartinus
3个回答

3
我认为目前在JDK中没有公开获取当前CPU的调用,尽管它已经被之前讨论过1,并且被提出作为JDK增强
我认为在实现类似功能之前,最好的方法是使用像JNA(最简单)或JNI(速度快)这样的东西来包装一个本地系统调用,例如Linux上的getcpu或Windows上的GetCurrentProcessorNumber
至少在Linux上,getcpu在VDSO中实现,无需内核转换,因此只需要几个纳秒,再加上JNI调用需要几个纳秒。 JNA速度较慢。
如果您真的需要速度,您可以将该函数作为内置函数添加到定制的JVM中(因为OpenJDK是开源的)。 这将减少几个纳秒。
请记住,这些信息可能会很快过时,因此您不应该仅依赖它来保证正确性,而应该关注性能。由于您已经需要处理获取“错误”值的情况,另一个可能的方法是将CPU ID的缓存值存储在ThreadLocal中,并定期更新它。这使得诸如解析/proc文件系统之类的慢速方法可行,因为您只会偶尔使用它们。为了获得最大的速度,您可以定期从计时器线程无效化线程本地,而不是在每次调用时检查无效化条件。

1 讨论和增强请求都是非常推荐的阅读材料。


1

有一个相关的Linux问题没有令人满意的答案(解析top输出不算,并且被接受的答案已经不再适用)。我认为

/proc/<pid>/task/<tid>/sched

可能会以类似这样的一行给出这些信息。
 current_node=0, numa_group_id=0

但是在我的i5-2400上运行4.4.0-92通用内核时,所有线程的这一行始终相同。我猜,“node”表示一个完整的CPU(插座),而我只有一个。

我找不到任何关于此的文档,或者在此文档中错过了它。


然而,我担心这些信息的获取可能对你没有帮助:
  • 从proc文件系统读取在你的工作规模上成本可能太高。
  • ThreadLocal不同,你的CoreLocal不是线程安全的:将线程迁移到另一个核心可能会破坏甚至微不足道的非原子操作,比如someCoreLocalField++。暂停它也会这样做。因此,你需要一些原子操作或线程局部变量来使其正常运行,这可能会使它变得过于缓慢,超出你的预期。

0

你可以查看/proc/[pid]/status

以下字段可能会有所帮助:

Cpus_allowed:此进程可运行的CPU掩码

Cpus_allowed_list:与上述相同,但以“列表格式”表示


那不是问题。 - Stefan Reich

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