【问题标题】:Why does this node.js loop run slowly after 112050 iterations?为什么这个 node.js 循环在 112050 次迭代后运行缓慢?
【发布时间】:2013-01-11 07:05:16
【问题描述】:

我在玩 node.js,发现这个简单的程序运行得非常慢,我什至没有等到 3 分钟过去后花了多长时间。

var fs = require ('fs')
var s = fs.createWriteStream("test.txt");
for (i = 1; i <= 1000000; i++)
      s.write(i+"\n");
s.end()

我尝试使用不同的值,发现 1-112050 需要 3 秒,而 1-112051 需要一分钟。这种突然下降很奇怪。 python 中的相同程序或等效的 shell 脚本“seq 1 112051”在合理的时间内(0-2 秒)运行。

请注意,这个 node.js 应用运行得更快:

var fs = require('fs')
     , s = []
for (var i = 1; i <= 1000000; i++) s.push(i.toString())
s.push('')
fs.writeFile('UIDs.txt', s.join('\n'), 'utf8')

谁能向我解释为什么 node.js 会这样,以及为什么下降如此突然?

【问题讨论】:

  • 我可以确认这发生在我的 Linux VM 上:0m2.372s1m0.039s。这个数字如此圆的事实让我认为这可能是写入流深处的超时。我会仔细研究一下。
  • 另外,当使用strace 时,它在第一种情况下显着减慢 - 到0m7.259s 但在第二种情况下速度相同 - 1m6.462s,让我怀疑更进一步。
  • 数据的size是与退化性能直接相关的(如果是,大小是多少,以字节为单位)还是number i> 的 write 电话?

标签: node.js performance loops file-io io


【解决方案1】:

这是一个被填满的缓冲区。每次写入都会根据内核缓冲区的状态返回truefalse

如果你开始监听返回码并使用drain事件,它至少会在速度上保持一致。

var fs = require ('fs') 

function runTest(stop) {
  var s = fs.createWriteStream("test.txt");
  var startTime = Date.now();
  var c = 1;
  function doIt() {
    while (++c <= stop) {
      if (!s.write(c+"\n")) {
        s.once('drain', doIt);
        return;
      }
    }

    s.end();
    var diffTime = Date.now() - startTime;
    console.log(stop+': took '+diffTime+'ms, per write: '+(diffTime/stop)+'ms')
  }

  doIt();
}

runTest(10000);
runTest(100000);
runTest(1000000);
runTest(10000000);
runTest(100000000);

输出:

$ node test.js
10000: took 717ms, per write: 0.0717ms
100000: took 5818ms, per write: 0.05818ms
1000000: took 42902ms, per write: 0.042902ms
10000000: took 331583ms, per write: 0.0331583ms
100000000: took 2542195ms, per write: 0.02542195ms

【讨论】:

  • 这些测试交错。只要第一个runTest(10000) 命中s.once('drain', doIt);,下一个runTest(100000) 就已经开始运行。您可以通过在函数顶部插入console.log('Testing '+stop+'...'); 来验证这一点。
【解决方案2】:

这是因为for 循环是同步的,但Writable.write() 不是。对于您的示例 s.write 创建 一百万 个块队列。这会导致超过 一百万 个函数调用 (like this) 来处理此队列。所以,Writable.write 不是为小块设计的。您可以check sourcesWritable.write 获取更多信息。

【讨论】:

  • 很公平,但是为什么在 112050 上仅一个调用的差异就会使处理时间从 3 秒跳到 1 多分钟?
  • @TonyBiondo,可能是任何东西......可能与 IO 链中 something 的缓冲区大小有关。实验。
  • 多亏了这一点,我将输出排入队列,每百万个项目只调用write,这大大加快了速度:)
【解决方案3】:

我相信这可能是特定于环境的,您在什么情况下编写此代码? 例如,最初我认为它是用于网站的,但它涉及到编写文件,这让我很反感。

否则,根据实现,使用文件系统的工作很有趣,我不应该责怪编程语言,但我真的不知道 javascript 如何处理特定系统上的文件 IO,文件 IO 的性能是一门科学自己的权利,可能与计算机科学本身一样古老。

【讨论】:

  • 如果你对 node.js 环境完全不熟悉,你应该不理会这个问题。
猜你喜欢
  • 1970-01-01
  • 2021-10-14
  • 2019-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-29
  • 2019-09-09
  • 1970-01-01
相关资源
最近更新 更多