我写了一个用广度优先搜索来解决N字谜问题的算法.为了加快速度,我决定预先分配一个大数组,而不是重复推送和将值转移到空数组。
偶然地,我注意到一种奇怪的行为,分配大数组两次实际上加快了挂钟的时间。我用完整代码创建了一个要点,但让我感到奇怪的部分是:
var values = new Array(1000000);
function breadthFirstSearch(state, goalState) {
values = new Array(1000000);
// implementation of a breadth first search for the n-puzzle problem
}在我的机器上,当值两次使用node.js初始化时,典型的运行时大约是550 my。当我注释掉其中一个我正在实例化值的地方时,运行时就会增加到650 to 700 to。在我看来,当只分配数组一次时,运行时应该会减少。我创建了一个视频来解释我在做什么,它显示了我的机器这里上的运行时间。
奇怪的是,当我在repl.it上运行它时,不管它是否被注释掉,运行时都是相同的,这让我认为它与v8引擎有关。
有人能给我解释一下为什么在做应该少做的事情时,墙上的时钟时间会增加吗?
发布于 2015-06-18 04:00:30
我在评论中写了这个答案中的大部分内容,因为在写这些评论时,这个问题已经锁定了。
我用更好的时间测量调用扩展了原始代码,这些调用使用performance.now,它可以在现代浏览器中使用,也可以作为节点模块performance-now使用。代码被上传为这个要旨。
我改变的是:
function init(),它(Re)初始化所有全局变量,否则程序将无法在多个运行中工作。function breadthFirstSearch复制到breadthFirstSearchUncommented和breadthFirstSearchCommented中,第一个在每个调用中初始化values = new Array(1000000);,第二个调用按原样使用全局变量values,即前面提到的语句被注释/删除。function time以接受应该使用哪个BFS函数。function measureTime,它使用给定的BFS函数参数和runs (参数)度量的min、max和平均值来调用time。最后,它输出总时间(所有time调用的时间之和)。这个函数的代码在下面,当然在gist上,在index.js文件的末尾。measureTime调用的开始和结束。函数measureTime
function measureTime(bfsFn, label, runs) {
console.log('starting', runs, 'measures for', label);
var diff = 0;
var min = Number.MAX_VALUE, max = Number.MIN_VALUE;
for (var i = 0; i < runs; i++) {
init();
var start = now();
time(bfsFn);
var d = now() - start;
diff += d;
min = Math.min(d, min);
max = Math.max(d, max);
}
var avg = diff / runs;
console.log('%s - total time for %d measures: %sms', label, runs, diff.toFixed(3));
console.log('%s - avg time: %sms (%sms - %sms, Δt = %sms)',
label, avg.toFixed(3), min.toFixed(3), max.toFixed(3), (max - min).toFixed(3));
}实际答案是:问题是为什么程序定义新数组两次,即一次在开始时,一次在每次BFS函数调用时,比初始化代码注释时更快。
答案是,这是没有解释的。这不是JavaScript VM工作方式的结果,也不是任何JavaScript的怪癖,而是简单得多:所讨论的语句实际上是假的。
OP所说的话,以及后来提供视频解释的好意,只适用于一次运行。最重要的原因是,正如我们都知道的,现代操作系统同时做了很多工作--我知道这不是完全正确的,但是为了这个解释,请原谅我。这意味着在多个运行中很难有完全相同的运行时,因此我们看到了多个运行中执行时间的一些波动。
为了获得更精确的度量,我为每个注释调用了函数measureTime 100次,对未注释的函数调用了100次。这创造了一个样本,使波动最小化。
我为不同的执行环境创建了比较表。所有测试都是在上运行的,使用的是最新的稳定版本的浏览器和自2015年6月18日起使用的io.js。
| Environment | Uncommented time [ms] | Commented time [ms] |
| :-------------- | :---------------------- | :-------------------- |
| Chrome | 460.254 | 424.725 |
| Firefox | 796.471 | 781.662 |
| Safari | 529.492 | 474.580 |
| Node.js (io.js) | 411.804 | 394.807 |这是我能做的最好的表,因为Stack溢出不支持表标记。对于实际的表样式,请看一看https://gist.github.com/markogresak/89f8d318e1f8ccb5187c。
在本表中,很明显,使用未注释的数组重新初始化代码的原始语句更快,因为我们可以看到,这对于我测试过的所有四个环境都是错误的。
这里要吸取的教训是,不要仅仅根据几次运行就得出性能结论。应该收集多个测试运行的数据,并解释所有值的平均值,或者在某些情况下,应该使用更复杂的统计方法来获得更准确的结果。
https://stackoverflow.com/questions/30903209
复制相似问题