【问题标题】:Why calling a function in generator runs faster?为什么在生成器中调用函数运行得更快?
【发布时间】:2019-06-18 03:12:14
【问题描述】:

function* test() {
  console.time("function-call")
  loop();
  console.timeEnd("function-call");

  console.time("in-function");
  var i, j;
  i = 0;
  while (i < 10000) {
    j = 0;
    while (j < 10000) {
      j++
    }
    i++;
  }
  console.timeEnd("in-function");
}

function loop() {
  var i, j;
  i = 0;
  while (i < 10000) {
    j = 0;
    while (j < 10000) {
      j++
    }
    i++;
  }
}

test().next();

我复制了“循环”中的代码块,并粘贴到“测试”函数中以比较时间。

function-call: 84ms 
in-function: 596ms

调用函数比在函数内部循环要快得多。为什么会这样?

【问题讨论】:

  • 我的猜测是优化器意识到你的循环函数没有做任何事情(ij 不能在循环外访问,循环内什么也没有发生),所以它是优化了。但是由于某种原因,当循环处于更大的上下文中时,相同的优化不会捕获。
  • 在 Chrome(v8 引擎)上,in-function 稍快。在 Firefox 上,我复制了您的结果。有趣的问题
  • @JoachimSauer 实际上,我有类似的代码块可以做一些事情。我准备了一个简化版来问。
  • 在节点 js 函数调用上测试:154.183ms,函数内:152.907ms,@Cory,你能附加你的原始代码吗。
  • 有趣的是,将 in-function 函数包含在 IIFE 中,它运行得更快。所以@JoachimSauer 的猜测可能是 100% 正确的。也许我们不应该问为什么function-call 更快,但为什么in-function 更慢

标签: javascript firefox v8 geckodriver firefox-quantum


【解决方案1】:

@Cristian Traìna 节点不允许跳过空循环。这些优化只允许在带有-O2 等标志的编译语言中,如 Pascal 或 C/C++。

对于这个程序

var max=process.argv[2];
for(var i=0;i<=max;i++){} // with let results is the same

我们可以从多个循环中获得以下执行时间的依赖关系。它是一个 LogLog 图表。它支配部分执行时间的第一个平坦区域是 NodeJs 的启动。在 1M 循环之后,您可以看到迭代次数随时间线性增加。最高测量大约需要 1000 秒,因此 V8 不会跳过空循环。


(来源:gustawdaniel.pl

从问题回到脚本:

  • 铬 71.0.3578.98
function-call: 154.878662109375ms
in-function: 153.7490234375ms
  • 节点 v10.15.0
function-call: 154.183ms
in-function: 152.907ms
  • Firefox 量子 64.0
function-call: 156 ms debugger eval code:4:3
in-function: 1519 ms
  • 铬 71.0.3578.98
function-call: 158.954345703125ms
in-function: 153.663818359375ms
  • 维瓦尔第 2.2
function-call: 153.548095703125ms
in-function: 153.755126953125ms
  • 歌剧 58.0.3135.47
function-call: 154.34814453125ms
in-function: 154.729248046875ms

我朋友的电脑测试:

  • 边缘
function-call: 3 496,6 ms
in-function: 2 330,9 ms
function-call: 70.69580078125ms
in-function: 70.43310546875ms

所以现在看来​​是 Firefox 和 Edge 的问题。

除 Firefox 和 Edge 之外的任何这些浏览器都使用 V8 引擎。火狐在这里描述:

https://www.digitaltrends.com/web/mozilla-firefox-new-browser-engine-quantum-2017/

并使用Quantum Flow:

Edge 团队考虑采用 Chromium 引擎

https://www.pcmag.com/news/365345/microsofts-edge-browser-to-adopt-googles-chromium-engine

来自这篇文章

https://blog.mozilla.org/blog/2018/12/06/goodbye-edge/

我们可以看到以后只支持Chromium from GoogleGecko Quantum from Mozilla

如果有人可以访问 Safari 或 Edge,请附加测试。

【讨论】:

  • 好吧,我从来没有说过 V8 会跳过空循环,但即使我没有说,它可能仍然是真的。即使 JavaScript 不是一种编译语言,最现代的引擎也会执行一些即时编译并提前观察代码,以便对代码进行一些预测和优化。如果我没记错的话,V8 使用至少两个线程,一个用于优化,一个用于执行
  • 我同意you did not say it 并且它可能可能是真的。我观察到只在编译语言中跳过空循环,并且只使用特殊标志。
  • 我的意思是 Node 在这个任务中没有特别优化,因为他的速度对于许多脚本语言(如 php、perl、python、ruby)来说是空循环中的典型速度,并且 node 在这个组中。这是一个没有这个特殊标志的循环执行时间的对数图表(较小的值 - 更快)blog.gustawdaniel.pl/content/images/2019/01/speed-2.png
猜你喜欢
  • 2012-06-29
  • 1970-01-01
  • 2015-10-24
  • 2013-05-17
  • 2012-09-13
相关资源
最近更新 更多