如何确定 Java 线程在哪个内核上运行?

2022-09-04 04:38:10

我想实现一个CoreLocal映射,它的工作方式与ThreadLocal一样,只是它返回一个特定于当前线程运行的核心的值。

这样做的原因是我想编写将从队列中获取作业的代码,但我想优先考虑那些其关联数据已经位于与从队列中选取作业的线程位于同一 L1 缓存中的作业的作业。因此,我希望每个内核都有一个队列,而不是整个程序的一个作业队列,只有当队列为空时,工作线程才会查看其他内核的队列。


答案 1

我不认为有任何调用来获取当前CPU当前在JDK中公开,尽管它之前肯定已经讨论过1作为JDK增强功能提出

我认为在实现类似的东西之前,你最好的选择是使用像JNA(最简单)或JNI(快速)这样的东西来包装一个原生系统调用,比如Linux上的getcpu或Windows上的GetCurrentProcessorNumber

至少在Linux上,它是在没有内核转换的VDSO中实现的,所以它只需要几纳秒,再加上几个纳秒的JNI调用。JNA的速度较慢。getcpu

如果你真的需要速度,你总是可以把这个函数作为一个定制的JVM的固有功能添加进来(因为OpenJDK是开源的)。这将减少更多的纳秒。

请记住,这些信息一旦获得它就可能过时,因此您永远不应该依赖它的正确性,而只能依靠性能。由于您已经需要处理获取“错误”值的问题,因此另一种可能的方法是将 CPU ID 的缓存值存储在 中,并且仅定期更新它。这使得解析文件系统等慢速方法可行,因为您很少这样做。为了获得最大速度,您可以从计时器线程定期使线程本地失效,而不是在每次调用时检查失效条件。ThreadLocal/proc


1 强烈建议阅读讨论和增强请求。


答案 2

有一个相关的linux问题没有令人满意的答案(解析输出不计算在内,接受的答案不再有效)。我以为top

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

可能会在以下行中提供此信息

 current_node=0, numa_group_id=0

但是在我的i5-2400上运行4.4.0-92通用内核上,这条线对于所有线程总是相同的。我想,“节点”意味着一个完整的CPU(插槽),而我只有一个。

我找不到这方面的文档,或者本文档中遗漏了它。


但是,我担心获取此信息可能会对您有所帮助:

  • 从proc文件系统中读取对于您正在处理的规模来说可能过于昂贵。
  • 与 不同,您的线程不是线程安全的:将线程迁移到另一个内核甚至会破坏琐碎的非原子操作,例如.暂停它也可以做到这一点。因此,您需要一些原子或线程局部变量才能使其正常工作,这再次可能使其对于您想要的来说太慢了。ThreadLocalCoreLocalsomeCoreLocalField++

推荐