0

我有一个函数可以从数据库中获取线程(gmail会话)ID,然后向Google API请求每个线程ID的所有数据。一旦它收到一个线程对象,它将它存储到数据库中。这适用于我的收件箱,其中有1k条消息。但我不确定它是否适用于超过10万条消息的帐户。只要有足够的RAM可用,是否会有大量回调中断脚本或继续执行?

现在我所问,一旦机器内存不足,它会破坏还是继续执行回调函数,只要有足够的RAM可用?如果您运行的内存我应该修改这个代码来执行此部分的部分(重办整个脚本在某些点,并继续从那里最后结束的新鲜RAM?)

function eachThread(auth) { 
    var gmail = google.gmail('v1'); 

    MongoClient.connect(mongoUrl, function(err, db){ 
    assert.equal(null, err); 
    var collection = db.collection('threads'); 
    // Find all data in collection and convert it to array 
    collection.find().toArray(function(err, docs){ 
     assert.equal(null, err); 
     var threadContents = []; 
     // For each doc in array... 
     for (var i = 0; i < docs.length; i++) { 
     gmail 
     .users 
     .threads 
     .get({auth:auth,'userId':'me', 'id':docs[i].id}, function(err, resp){ 
      assert.equal(null, err); 
      threadContents.push(resp); 
      console.log(threadContents.length); 
      console.log(threadContents[threadContents.length - 1].id); 
      var anotherCollection = db.collection('threadContents'); 
      anotherCollection.updateOne(
      {id: threadContents[threadContents.length - 1].id}, 
      threadContents[threadContents.length - 1], 
      {upsert:true}, 
      function(err, result){ 
       assert.equal(null, err); 
       console.log('updated one.'); 
      }); 
      if (threadContents.length === docs.length) { 
      console.log('Length matches!'); 
      db.close(); 
      } 
     });//end(callback(threads.get)) 
     }//end(for(docs.length)) 
    });//end(find.toArray) 
    });//end(callback(mongo.connect)) 
}//end(func(eachThread)) 
+0

我不知道是不是因为内存,但我确实记得在SQL中部分实现了MongoDB工具。在测试不同尺寸的零件之前,零件版本的零件速度要快2倍。 – DrakaSAN

+0

@DrakaSAN我完全一样。我有mySQL数据库有数百万行,并且我做了一个CRON,它部分地从SQL迁移到mongo。但那是PHP。我相信这个回调世界可能会更好地工作一次,无论需要多长时间,我只需要它来完成这项工作。 – Kunok

+1

你可以做的是避免'threadContents'并插入'resp'本身。你也在循环内创建'anotherCollection',这是毫无意义的,因为它一次又一次地是同一个对象。那么你肯定会没有任何问题与内存。 – sed

回答

2

你不会用完的内存,如果你不会得到的一切,并把它推到阵列。此外,我不会在循环内的每个元素上实例化相同的对象。

下面是不会耗尽内存的代码的示例,但它是“即忘即忘”,意味着在完成时不会收到回调。如果您希望这样做,您需要使用promises /异步。

// Fire-and-forget type of function 
// Will not run out of memory, GC will take care of that 
function eachThread(auth, cb) { 
    var gmail = google.gmail('v1'); 

    MongoClient.connect(mongoUrl, (err, db) => { 
    if (err) { 
     return cb(err); 
    } 

    var threadsCollection = db.collection('threads').find(); 
    var contentsCollection = db.collection('threadContents'); 

    threadsCollection.on('data', (doc) => { 
     gmail.users.threads.get({ auth: auth, 'userId': 'me', 'id': doc.id }, (err, res) => { 
     if (err) { 
      return cb(err); 
     } 

     contentsCollection.updateOne({ id: doc.id }, res, { upsert: true }, (err, result) => { 
      if (err) { 
      return cb(err); 
      } 
     }); 
     }); 
    }); 

    threadsCollection.on('end',() => { db.close() }); 
    }); 
} 
+0

您添加了'cb'作为参数。这基本上是回调变量,不需要先定义或我需要定义它的地方? – Kunok

+0

这是一个用于错误处理的cb。 'eachThread('my auth',(err)=> {if(err){console.error(err)}})'这里是一个例子。 – sed

+0

我得到这个错误:'TypeError:cb不是一个函数' – Kunok

1

Now what I am asking, once a machine runs out of memory, will it break or will it continue executing callback functions whenever enough RAM is available again?

,操作系统会杀死你的进程。在Linux中你会看到一个OOM(内存不足)。所以是的,它会破裂。

在这些场景中,您可能会考虑使用流或生成器,以便只保留需要处理的大量数据。

在你的情况MongoDB提供find方法https://mongodb.github.io/node-mongodb-native/2.0/tutorials/streams/

像这样的东西应该工作流:

var collection = db.collection('threads'); 
var cursor = collection.find() 

cursor.on('data', function(doc) { 
    gmail 
    .users 
    .threads 
    .get({auth:auth,'userId':'me', 'id': doc.id}, function(err, resp) { 
    ... 
    }) 
}) 
1

免去您for循环由async.mapLimit是足够多的部分功能添加的部分。我也冒昧地将anotherCollection的创作与collection并列在一起,因为一旦打开连接比打开连接好几千次都好。

我也用callback(err)替换了assert.equalasync的函数会理解它应该停止一切,并且它允许您干净地退出而不是抛出异常。

编辑:

由于@chernando说,使用collection.find().toArray将导入整个收集到RAM中。更好地完成零件的方法是传输数据,或要求数据库按块传递数据。

这个版本假设你有足够的RAM来让collection.find().toArray工作没有问题。

我稍后可能会回来,并在适当的时候改编我在评论中谈到的工具。

var async = require('async'); 

function eachThread(auth) { 
    var gmail = google.gmail('v1'), 
     limit = 100; //Size of the parts 

    MongoClient.connect(mongoUrl, function(err, db){ 
    assert.equal(null, err); 
    var collection = db.collection('threads'), 
     anotherCollection = db.collection('threadContents'); 
    // Find all data in collection and convert it to array 
    collection.find().toArray(function(err, docs){ 
     assert.equal(null, err); 
     var threadContents = []; 
//Change here 
     async.mapLimit(docs, limit, (doc, callback) => { 
     gmail 
     .users 
     .threads 
     .get({auth:auth,'userId':'me', 'id':docs[i].id}, function(err, resp){ 
      if(err) { 
      return callback(err); 
      } 
      threadContents.push(resp); 
      console.log(threadContents.length); 
      console.log(threadContents[threadContents.length - 1].id); 
      anotherCollection.updateOne(
      {id: threadContents[threadContents.length - 1].id}, 
      threadContents[threadContents.length - 1], 
      {upsert:true}, 
      function(err, result){ 
       if(err) { 
       console.error(err); 
       } else { 
       console.log('updated one.'); 
       } 
       callback(err); 
      }); 
     });//end(callback(threads.get)) 
//Change here 
     }, (error) => { 
     if(error) { 
      console.error('Transfert stopped because of error:' + err); 
     } else { 
      console.log('Transfert successful'); 
     } 
     });//end(async.mapLimit) 
    });//end(find.toArray) 
    });//end(callback(mongo.connect)) 
}//end(func(eachThread)) 
+2

请注意,'collection.find()。toArray'会急切地消耗你的RAM。 –

+0

@chernando:真的好点 – DrakaSAN

+0

好吧,我会继续关注这个答案,直到你稍后再回来。 – Kunok

相关问题