使用map()在大集和回调上的Javascript内存消耗

时间:2014-09-16 11:49:18

标签: javascript performance

我甚至不知道如何正确地提出这个问题,但我担心以下代码的性能(主要是内存消耗)。我预计这段代码会消耗大量内存,因为大型集合上的map和很多“挂起”的内容会消耗大量内存。等待外部服务的功能。我的担忧在这里是否合理?什么是更好的方法?

var list = fs.readFileSync('./mailinglist.txt') // say 1.000.000 records
  .split("\n")
  .map( processEntry );

var processEntry = function _processEntry(i){
  i = i.split('\t');
  getEmailBody( function(emailBody, name){
      var msg = {
      "message" :  emailBody,
      "name" : i[0]
      }
      request(msg, function reqCb(err, result){
        ...
      });
  }); // getEmailBody
}

var getEmailBody = function _getEmailBody(obj, cb){
// read email template from file; 
// v() returns the correct form for person's name with web-based service
  v(obj.name, function(v){
    cb(obj, v)
  });
}

2 个答案:

答案 0 :(得分:1)

如果您担心在很短的时间内提交一百万个http请求(您可能应该这样做),则必须设置某种缓冲区。

一种简单的方法:

var lines = fs.readFileSync('./mailinglist.txt').split("\n");

var entryIdx = 0;
var done = false;

var processNextEntry = function () {
    if (entryIdx < lines.length) {
        processEntry(lines[entryIdx++]);
    } else {
        done = true;
    }
};

var processEntry = function _processEntry(i){
  i = i.split('\t');
  getEmailBody( function(emailBody, name){
      var msg = {
      "message" :  emailBody,
      "name" : name
      }
      request(msg, function reqCb(err, result){
        // ...
        !done && processNextEntry();
      });
  }); // getEmailBody
}

// getEmailBody didn't change

// you set the ball rolling by calling processNextEntry n times,
// where n is a sensible number of http requests to have pending at once.

for (var i=0; i<10; i++) processNextEntry();

编辑:根据this blog post节点有一个内部队列系统,它只允许同时发出5个请求。但是如果你担心内存消耗,你仍然可以使用这种方法来避免用百万项填充内部队列。

答案 1 :(得分:1)

首先,我建议不要使用readFileSync,而是支持异步等效。应该避免阻止IO操作,因为从磁盘读取非常昂贵,虽然这是您现在代码的唯一目的,但我会考虑将来可能会如何改变 - 并且任意浪费时钟周期从来都不是好主意。

对于大型数据文件,我会以定义的块读取它们并处理它们。如果您可以提出一些模式,要么是标记来区分文件中的数据块,要么填充到边界,然后逐个处理文件。

这只是粗糙的,未经测试的是我的头顶,但有点像:

var fs = require("fs");

function doMyCoolWork(startByteIndex, endByteIndex){

    fs.open("path to your text file", 'r', function(status, fd) {

            var chunkSize = endByteIndex - startByteIndex;
            var buffer = new Buffer(chunkSize);

            fs.read(fd, buffer, 0, chunkSize, 0, function(err, byteCount) {

                var data = buffer.toString('utf-8', 0, byteCount);

                // process your data here


                if(stillWorkToDo){
                    //recurse
                    doMyCoolWork(endByteIndex, endByteIndex + 100);
                }
            });
        });
}

或者查看其中一个流库函数以获得类似的功能。

H2H

PS。 Javascript和Node在异步和事件方面运行得非常好..在我看来,使用sync是一种反模式,可能会导致代码在将来成为头疼的问题