2012-09-07 20 views
3

我使用下面的代码循环插入1000000文件到mongodb,但我发现节点进程占用大量内存,我的客户端已经死亡。[Node.js]通过本机驱动程序循环插入1000000个文件到mongodb,为什么节点占用大量内存?

db.collection("batch_insert", function (err, collection) { 
    if (!err) { 
     var count = 0; 
     for (var i = 0; i < 1000000; i++) { 
      collection.insert({hello:'world', ok:'OKOKOK'}, {safe:true, serializeFunctions:false}, function (err, result) { 
       count++; 
       if (1000000 == count) { 
        db.close(); 
       } 
      }); 
     } 
    } else { 
     console.log(err); 
    } 
}); 
+0

你知道这不是批量插入吗? – soulcheck

+0

我不知道节点如何管理这个,但是你在这里创建了100万个闭包。这可能会有点沉重吗? – Thilo

回答

3

与其他数据库一样,mongodb需要一些时间来处理请求。你向它投掷了一百万个请求,并且由于你的代码块中没有任何内容,这意味着在任何时候都有一大堆请求会在某个地方排队(最有可能在多个地方,其中一些位于驱动程序的内部代码,其他节点的事件循环内)。这需要超过一点点的记忆。

如果排队没有发生,你可以阻止或放弃一些请求。有没有这样的免费午餐。

+0

如果我正确理解了节点,就没有后台线程,所以*队列中的所有*将在队列开始处理之前排队(或至少在第一个完成回调被触发之前)。 – Thilo

+0

mongo驱动程序的编写方式可以在处理请求时在内部执行一些异步操作。 – ebohlman

+0

好的。但是,在排队循环完成之前,回调不会被执行(并且出列),对吧? – Thilo

8

您的for周期会阻止事件循环。并且它不能去nextTick并处理查询结果,直到所有查询发送到mongodb。您需要使用异步方式批量插入数据。 类似这样的:

var mongo = require('mongodb'); 

var Inserter = function (collection) { 
    this.collection = collection; 
    this.data = []; 
    this.maxThreads = 6; 
    this.currentThreads = 0; 
    this.batchSize = 5000; 
    this.queue = 0; 
    this.inserted = 0; 
    this.startTime = Date.now(); 
}; 

Inserter.prototype.add = function(data) { 
    this.data.push(data); 
}; 

// Use force=true for last insert 
Inserter.prototype.insert = function(force) { 
    var that = this; 
    if (this.data.length >= this.batchSize || force) { 
     if (this.currentThreads >= this.maxThreads) { 
      this.queue++; 
      return; 
     } 
     this.currentThreads++; 
     console.log('Threads: ' + this.currentThreads); 
     this.collection.insert(this.data.splice(0, this.batchSize), {safe:true}, function() { 
      that.inserted += that.batchSize; 
      var currentTime = Date.now(); 
      var workTime = Math.round((currentTime - that.startTime)/1000) 
      console.log('Speed: ' + that.inserted/workTime + ' per sec'); 
      that.currentThreads--; 
      if (that.queue > 0) { 
       that.queue--; 
       that.insert(); 
      } 
     }); 
    } 
}; 

var db = new mongo.Db('test', new mongo.Server('localhost', 27017, {}), {native_parser:false}); 
db.open(function(err, db) { 
    db.collection('test', function(err, collection) { 
     var inserter = new Inserter(collection); 
     setInterval(function() { 
      for (var i = 0; i < 5000; i++) { 
       inserter.add({test:'test'}); 
      } 
      inserter.insert(); 
     }, 0); 
    }); 
}); 
+1

我不能满足这个答案。 – StuR

+0

我有一个稍微不同的问题,但您的评论指出我在正确的方向。感谢名单! –

+0

这种方法存在巨大的内存泄漏。通过只插入2000个条目,我的内存使用量猛增到1 GB。 – Angelin

相关问题