【问题标题】:node.js : async.each gets too slow with large number of elements to process asynchronouslynode.js:async.each 因大量元素而变得太慢而无法异步处理
【发布时间】:2015-03-24 19:25:24
【问题描述】:

我有一个 4GB 内存的系统。我需要按以下方式处理一组 200 个文件(平均文件大小 = 20MB):

  • 从 gridfs 读取每个文件
  • 从文件中提取一些信息
  • 将信息存储到 mongoDB 中的某个集合中

现在的代码是:

async.each(files, function (file, callback){

    console.log("reading file", file._id);

    readstream[file._id] = db.gfs().createReadStream({
        _id: file._id
    });

    readstream[file._id].on('data', function (chunk) {
        part[file._id] = part[file._id] && (part[file._id] + chunk.toString()) || chunk.toString();
    });

    readstream[file._id].on('end', function(){

        //  do something here 

    });

}, function (err){
    if(err){
        console.error("error ", err);
        res.json(err);
    }               
    else{
        console.log("saved all files ############ YIPPIEEEEEEEEEEEEE ###################");
        res.json({"status": 1});
    }
});

它就像 10 个文件的魅力一样。当文件数量很大(在我的情况下为 200 个)时,它会变得非常慢,可能是由于内存限制。

目前,我可以一次处理 10 个文件,并且可以使用它,因为它是一次性活动。但我想知道在生产中处理此类情况的标准做法是什么?

【问题讨论】:

  • 这些文件有多大?如果是内存问题,那么最终您需要查看硬件,这里的正确方法是横向扩展而不是纵向扩展。
  • async.each 接受所有任务并并行执行它们,尝试使用async.eachSeries 而不是一个接一个地执行任务,如果您仍然需要并行执行,您可能想看看async.cargo,它基本上是“each, and eachSeries”的组合。
  • 也许你可以重构使用异步函数eachLimit link 或parallelLimit? link。这将并行执行最多指定数量的任务。也就是说,您可以将其限制为 10 次,它会运行前 10 次,然后随着 10 次中的每一次完成,它会开始另一个,直到全部完成。
  • @Ma'moonAl-Akash:async.eachSeries 成功了。谢谢!!! :-) 您可以将其发布为答案,以便我可以关闭此问题
  • 我将把这个作为答案发布,以便对其他人有用,请接受它以表明这有助于解决问题。

标签: node.js memory-management gridfs


【解决方案1】:

问题归结为并行执行因为async.each并行执行所有任务,作为一种变通方法,您可以使用async.eachSeries逐个执行任务,也可以考虑使用async.cargo结合在镜头中执行多个任务。

【讨论】:

  • 只是为了记录,虽然它的工作方式比 async.each 好得多,但是当文件数量和每个文件的大小很大(大约 100 个文件,每个文件 30 MB)时,即使这样也无济于事。
  • 试试async.cargo,分享你的经验
  • 我的错。它工作得很好。还有一个嵌套的 async.each 也导致了问题。现在也将其更改为 async.easchSeries。自 1 小时以来运行良好
【解决方案2】:

您也可以使用async.eachLimitlimit 这里是一次异步操作的最大数量。这将限制异步 并行运行 N 个任务。

异步文档:

与 each 相同,但在 a 处运行最多限制异步操作 时间。

示例(未测试,但这是一次处理 10 个文件的想法):

filesContent = []
async.eachLimit(fileNamesArray, 10, function(fileName, callback) {
    // Process a file
    processFile(fileName, (err, content) => {
        filesContent.push(content);
        callback(err);
    });
}, function(err) {
    // if any of tasks produced an error, err would equal that error
    if( err ) {
      console.log('A file failed to process');
    } else {
      console.log('All files have been processed successfully');
    }
});

【讨论】:

    猜你喜欢
    • 2017-08-07
    • 2016-08-26
    • 1970-01-01
    • 1970-01-01
    • 2016-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多