如何确定 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 线程在哪个内核上运行?的主要内容,如果未能解决你的问题,请参考以下文章

如何在多核上运行 Keras?

Linux 有问必答:如何知道进程运行在哪个 CPU 内核上?

执行线程的核心数

在 Java 中,如何确定线程是不是正在运行?

怎样才能找出哪个 CPU 内核正在运行该进程?

如何确定特定排毒测试在哪个平台上运行?