为了简单起见,我在这里使用了一个for循环来创建一个包含100万个对象的数组。
我想将数组中的每个对象发布到mongo db。
我的记忆力不足。
我知道我可以增加内存分配,但这不是我想要的解决方案。出于超出本示例范围的原因,我也不想使用mongo的批量方法。
我知道必须有一些发布这些对象的方法,这意味着每次迭代都会释放内存(垃圾收集?) - 谁能告诉我它是什么?
谢谢!
此处的当前代码供参考(导致分配错误):
var results = [];
for(var i = 1; i < 1000001; i++){
results.push({"num":i});
}
async = require("async");
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var mongoUrl = 'mongodb://root@localhost:27017/results';
MongoClient.connect(mongoUrl, function (err, db) {
var collection = db.collection('results');
// 1st para in async.each() is the array of items
async.each(results,
// 2nd param is the function that each item is passed to
function(item, callback){
// Call an asynchronous function, often a save() to DB
collection.insert(item, function (err, result) {
if(err) console.log(err);
console.log(item);
callback();
});
},
// 3rd param is the function to call when everything's done
function(err){
// All tasks are done now
db.close();
}
);
});
答案 0 :(得分:5)
async.each()
并行运行插入,因此它基本上启动了1000000个并发插入操作。
您可能希望使用async.eachLimit()
答案 1 :(得分:0)
如果要优化插入,请考虑使用bulk operation,因为它还会来回减少网络使用量。同时存储大量数组,特别是如果它们刚刚被计算出来会占用太多内存。
var bulk = collection.initializeUnorderedBulkOp();
var count = 1, i = 0;
var bulkSize = 1000;
var generator = function (mx) {
if(i < mx){
return {num: i++}
}
return null;
}
var run = function () {
doc = generator();
if(doc) {
bulk.insert(doc)
}
if(doc == null || count % bulkSize == 0) {
bulk.execute(function (err, res) {
if(err) {} // do something
if(doc == null) {
db.close
}
run();
})
}
}
run()
此处,程序的任何步骤都不会存储大数组。只有在创建批量数组时,您才会存储它。一旦达到bulkSize
答案 2 :(得分:0)
使用setImmediate来防止内存不足错误
var results = [];
for(var i = 1; i < 1000001; i++){
results.push({"num":i});
}
run(0, results.length, results, function(err){
// do stg
});
function run(done, todo, results, callback)
{
if(++done >= todo)
{
// return callback if all done
return callback(null);
}
else
{
// save one using index
//collection.insert(results[done], function(err, res){
// OR save one and remove it from results
collection.insert(results.splice(0,1),
if(err)
return callback(err);
else
{
// use setImmediate to recall run while releasing stack
return setImmediate(run, ++done, todo, results, callback);
}
});
}
}