如何在JavaScript中获取CPU核心数量?

78

有没有办法在JavaScript中确定可用的CPU核心数量,以便根据此调整Web Worker的数量?


7
“这台电脑有几个 CPU 核心?”普通用户对核心的了解甚至比 JS 还少 ;) - Piskvor left the building
2
为什么每个编写网页的人都假定他们可以控制我电脑的全部资源?我想在阅读您网页上所需的一小部分信息时完成其他事情。 - Gilbert Le Blanc
3
@meo: 为什么我想知道这个?如果一个系统只有1或2个核心,而我启动了4个Web工作者,则线程或进程(取决于浏览器如何实现Web工作者)可能会阻塞它们自己。通常情况下,启动的线程数量取决于可用核心数,这是非常普遍的。 - tsauerwein
在WHATWG邮件列表中也有关于这个问题的讨论:http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2009-November/024058.html - http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2009-November/023993.html - tsauerwein
5个回答

104

是的,引用MDN的话:

navigator.hardwareConcurrency 只读属性返回用户计算机上可用于运行线程的逻辑处理器数量...

现代计算机在其CPU中具有多个物理处理器核心(通常为两个或四个核心),但每个物理核心通常也能够使用先进的调度技术同时运行多个线程。因此,例如,四核CPU可能提供八个逻辑处理器核心。逻辑处理器核心的数量可用于测量可以有效地同时运行而无需它们进行上下文切换的线程数。

然而,浏览器可能会选择报告较低的逻辑核心数,以更准确地表示可以同时运行的Workers数量,因此不要将其视为用户系统中核心数量的绝对测量。

它受到除Internet Explorer之外的所有浏览器的支持。对于此问题,您可以使用polyfill core-estimator (演示博客文章)。


1
当我在Chrome 35中运行此代码时,它是未定义的。 - jamesmortensen
根据http://src.chromium.org/viewvc/blink?view=revision&revision=175629,它在当前的Chrome Canary版本中可用。已确认在Chrome Canary 37中运行正常。 - Bas van Dijk
2
它是某种标准的一部分吗(例如支持或者也意味着其他浏览器也会支持)? - jayarjo
1
一个安全的做法是使用 navigator.hardwareConcurrency || 4 来假设浏览器具有 4 线程能力,即使浏览器没有报告它。大多数 CPU 支持 4 或更多线程,即使在移动设备上也是如此。在拥有较少线程的 CPU 上,4 线程将被分时执行。请注意,线程计数可能与 CPU 核心数不同,因为许多 CPU 支持每个核心多个线程。一个 Intel 2 核心 CPU 将同时以硬件方式运行 4 个线程。 - Greg Searle
您可以在此处查看完整的支持表:https://www.caniuse.com/#feat=hardwareconcurrency - jocull
Greg Searly所说的一切都是正确的。即使它不正确,这也是一个有用的答案。navigator.hardwareConcurrency返回CPU优化“线程”的数量,通常但并非总是是CPU核心数的两倍。对于这个问题来说,核心数会更有用,因为匹配超线程计数只会让CPU做更多的上下文切换。更多细节请参见:https://askubuntu.com/questions/668538/cores-vs-threads-how-many-threads-should-i-run-on-this-machine - Josh

18

没有,除非你使用一些ActiveX。


虽然在 WHATWG 邮件列表中有关于在规范的第二版中提供类似属性的讨论: http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2009-November/024058.html http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2009-November/023993.html - tsauerwein
7
最终有一个 API 可供使用,可以查看现在被接受的答案。 - tsauerwein

14

12

这是我匆忙拼凑的一个相当快速的并发估计器... 目前还没有经过太多测试:

http://jsfiddle.net/Ma4YT/2/

以下是工作线程运行的代码(因为我提供了一个 jsfiddle 链接,所以必须提供一个示例):


// create worker concurrency estimation code as blob
var blobUrl = URL.createObjectURL(new Blob(['(',
  function() {
    self.addEventListener('message', function(e) {
      // run worker for 4 ms
      var st = Date.now();
      var et = st + 4;
      while(Date.now() < et);
      self.postMessage({st: st, et: et});
    });
  }.toString(),
')()'], {type: 'application/javascript'}));

估算器让大量的工作人员在短时间内(4ms)运行并报告他们运行的时间(不幸的是,在Web Workers中无法使用performance.now()进行更准确的计时)。然后,主线程检查同时运行的最大工作者数量。这个测试会重复多次,以获得足够的样本来产生一个估计值。

因此,主要思想是,在足够小的工作块的情况下,只有当有足够的核心支持该行为时,才应将工作者调度到同一时间运行。显然,这只是一个估计,但到目前为止,我测试过的一些机器已经相当准确 - 这对我的用例来说已经足够好了。可以增加样本数量以获得更准确的近似值;我只使用10个样本,因为它很快,我不想浪费时间进行估计而只是想完成工作。


2
如果你要在工作机器上进行数据处理,navigator.hardwareConcurrency可能不够好,因为它只返回现代浏览器中的逻辑核心数,你可以尝试使用WebCPU来估算物理核心数:
import {WebCPU} from 'webcpu';

WebCPU.detectCPU().then(result => {
    console.log(`Reported Cores: ${result.reportedCores}`);
    console.log(`Estimated Idle Cores: ${result.estimatedIdleCores}`);
    console.log(`Estimated Physical Cores: ${result.estimatedPhysicalCores}`);
});

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