mongoDB插入和process.nextTick

我有一个50k条目的列表,我正在进入我的分贝。

var tickets = [new Ticket(), new Ticket(), ...]; // 50k of them tickets.forEach(function (t, ind){ console.log(ind+1 + '/' + tickets.length); Ticket.findOneAndUpdate({id: t.id}, t, {upsert: true}, function (err, doc){ if (err){ console.log(err); } else { console.log('inserted'); } }); }); 

而不是预期的交错

 1 / 50000 inserted 2 / 50000 inserted 

我得到所有的插入确认信息

 1 / 50000 2 / 50000 ... 50000 / 50000 inserted inserted ... inserted 

我认为process.nextTick发生了一些事情。 几千条logging之后有一个显着的减速。

有谁知道如何获得高效的交错?

而不是预期的交错

这只是对于同步I / O的预期行为。

请记住,这些操作都是asynchronous的 ,这是node.js的一个主要思想。 代码做的是这样的:

 for each item in the list, 'start a function' // <-- this will immediately look at the next item output a number (happens immediately) do some long-running operation over the network with connection pooling and batching. When done, call a callback that says 'inserted' 

现在代码将会启动大量这些函数,然后将请求发送到数据库。 所有这些在第一个请求甚至到达数据库之前就已经发生了。 很可能操作系统甚至不打扰在实际发送第一个TCP数据包之前,比如票5或10等。

要回答您的评论中的问题:不,请求将会相对较快地发出(这取决于操作系统),但结果不会达到您的单线程JavaScript代码之前,您的循环没有完成排队50K条目。 这是因为forEach是你当前正在运行的一段代码,所有运行的事件只有在完成后才会被处理 – 如果你使用setTimeout(function() { console.log("inserted... not") }, 0)而不是实际的数据库调用,因为setTimeout也是一个asynchronous事件。

为了使你的代码完全asynchronous,你的数据源应该是某种提供数据的(asynchronous)迭代器,而不是大量的项目。

你遇到了节点不同步的奇迹。 它将upsert请求发送到ether中,然后继续到下一条logging,而不等待响应。 这是否重要,因为它只是一个信息性的消息,不与upsert同步。 如果需要确保按顺序完成,可能需要使用asynchronous库来翻转数组。