如何确定 Java 线程在哪个内核上运行?
Posted
技术标签:
【中文标题】如何确定 Java 线程在哪个内核上运行?【英文标题】:How can I determine what core a Java thread is running on? 【发布时间】:2013-02-27 07:29:12 【问题描述】:我想实现一个 CoreLocal 映射,它的工作原理就像 ThreadLocal,只是它返回一个特定于当前线程正在运行的核心的值。
这样做的原因是我想编写将从队列中获取作业的代码,但我想优先考虑其关联数据已经在与选择作业的线程相同的 L1 缓存中的作业从队列中。因此,我不想为整个程序设置一个作业队列,而是希望为每个内核设置一个队列,并且只有当队列为空时,工作线程才会查看其他内核的队列。
【问题讨论】:
github.com/peter-lawrey/Java-Thread-Affinity 听起来你的纳秒时间真的很低。 你有任何保证,一旦线程从队列中取出工作,它就不会被重新调度到另一个核心,从而使所有这些机制适得其反吗? Q==队列!将线程保持在具有热缓存的内核上比纳秒 (webtide.intalio.com/2012/12/…) 更有价值。我不知道线程可以跳过内核的频率或事件的频率,但您必须假设存在一些关联,否则缓存将根本不起作用。 @gregw 我想知道您是否可以在CoreLocal
上取得一些进展,或者它最终是如何解决的。
【参考方案1】:
也许你可以检查/proc/[pid]/status
这些字段可能会有所帮助:
Cpus_allowed:可以运行此进程的 CPU 掩码
Cpus_allowed_list:与之前相同,但采用“列表格式”
【讨论】:
这不是问题【参考方案2】:有一个相关的linux question 没有令人满意的答案(解析top
输出不计算在内,接受的答案不再起作用)。我以为
/proc/<pid>/task/<tid>/sched
可能会在一行中给出这些信息
current_node=0, numa_group_id=0
但是在我运行 4.4.0-92-generic 内核的 i5-2400 上,这条线对于所有线程总是相同的。我猜,“节点”是指整个 CPU(插槽),而我只有一个。
我找不到这方面的文档,或者在this document 中错过了它。
但是,我担心获取此信息可能无法帮助您:
从 proc 文件系统读取可能对您正在处理的规模过于昂贵。 与ThreadLocal
不同,您的CoreLocal
不是线程安全的:将线程迁移到另一个内核可能会破坏像someCoreLocalField++
这样的微不足道的非原子操作。暂停它也会这样做。因此,您需要一些原子或线程局部变量才能使其正常工作,这又可能使其速度太慢而无法满足您的要求。
【讨论】:
【参考方案3】:我认为没有任何调用来获取当前暴露在 JDK 中的 CPU,尽管它肯定是 previously discussed1 和 proposed as a JDK enhancement。
我认为,在实现类似的东西之前,最好的选择是使用JNA(最简单)或JNI(快速)之类的东西来包装本机系统调用,例如 Linux 上的 getcpu
或 Windows 上的 GetCurrentProcessorNumber
.
至少在 Linux 上,getcpu
是在没有内核转换的 VDSO 中实现的,因此它应该只需要几纳秒,再加上 JNI 调用的几纳秒。 JNA 比较慢。
如果您真的需要速度,您总是可以将该功能添加为定制 JVM 的内在函数(因为 OpenJDK 是开源的)。这将减少几纳秒。
请记住,这些信息可能会在您获得后立即过时,因此您永远不应依赖它的正确性,而只依赖性能。由于您已经需要处理获取“错误”值,另一种可能的方法是将 CPU ID 的缓存值存储在 ThreadLocal
中,并且只定期更新它。这使得诸如解析/proc
文件系统之类的慢速方法可行,因为您很少执行它们。为获得最大速度,您可以从计时器线程定期使本地线程无效,而不是在每次调用时检查无效条件。
1 强烈推荐阅读讨论和增强请求。
【讨论】:
以上是关于如何确定 Java 线程在哪个内核上运行?的主要内容,如果未能解决你的问题,请参考以下文章