我有一个Node.js服务器,它必须处理6个并发请求。 每个请求都从MonogDB数据库中读取文档,然后对其进行修改。
因此,当我们同时发送6个请求时,它们都读取相同的数据项并对其进行修改但我希望第一个请求修改的值应该由第二个请求读取,然后它应该能够进一步修改它,所以上。
例如, 我有一个名为x的数据项,初始值为' a'。 第一个请求将其修改为' ab'。所以,现在第二个请求应该是“ab'而不是'。但它总是写着' a'因为他们同时来了。
我曾尝试应用信号量,互斥量,async.series,async.waterfall,睡眠和承诺,但没有任何效果。可能我没有正确使用它们。那么,它们应该如何用于以同步方式处理这些并发请求。
或者还有其他方法吗?我们可以用时间戳订购协议做些什么吗?如果是,那么我如何在Node.js中应用它?
这是我想为这些并发请求运行的代码 -
app.get('/urltest', function (req, res) {
var q=require('url').parse(req.url,true).query;
var s=q.s;
MongoClient.connect(url, function(err, db) {
if(err)
throw err;
db.collection( 'Comp' ).find({no:2}).snapshot().forEach(
function (elem) {
db.collection( 'Comp' ).findAndModify (
{ no : elem.no },
[['no', 1]],
{ $set : { age:elem.age+s } }, {new:true},
function( err, result ) {
if ( err ) console.log( err);
console.log("after update: "+result.value.age);
res.end("success");
}
);
});
});
});
此处我同时发送了诸如 - http://192.168.197.140:8081/urltest?s=b,http://192.168.197.140:8081/urltest?s=c,http://192.168.197.140:8081/urltest?s=d等请求。
现在,他们可以按任何顺序运行。但我希望所有人都能在'' c',' d'等等。因此,每个人的输出应该看起来有点像 - ' ab',' abc'' abcd'等等。
但我得到的输出是' ab'' ac'' ad'。
我究竟应该如何使用promise来确保这些请求以同步方式执行?
答案 0 :(得分:2)
这听起来像一个复杂的系统。我的建议是看一下新的Mongo Node driver。 然后看看ECMAScript6 documentation。这涉及安装它使用的co模块。使用co就像使用promises一样(看一下模块)。它为您提供 yield ,它会返回一个承诺。
听起来你也需要聚合(如果我没有弄错的话。)对于a ab然后是abc等等。
应该通过等待yield返回来明显处理并发问题。新文档中的示例并不是很好,但足以让您从中获得一个有效的示例。
答案 1 :(得分:1)
您需要实施semaphore
。
了解here
在您的情况下,您必须一次提供一个请求,尽管它们“全部在一起”。所以
var sem = require('semaphore')(1);
var server = require('http').createServer(req, res) {
sem.take(function() {
// find, update and commit data before leaving the semaphore
expensive_database_operation(function(err, res) {
sem.leave();
if (err) return res.end("Error");
return res.end(res);
});
});
});
答案 2 :(得分:1)
所以,我所要做的就是正确实现信号量。 这是有效的代码的最终版本 -
var sem = require('semaphore')(1);
app.get('/urltest', function (req, res) {
sem.take(function() {
var q=require('url').parse(req.url,true).query;
var s=q.s;
MongoClient.connect(url, function(err, db) {
if(err)
throw err;
db.collection( 'Comp' ).find({no:2}).snapshot().forEach(
function (elem) {
db.collection( 'Comp' ).findAndModify (
{ no : elem.no },
[['no', 1]],
{ $set : { x:elem.x+s } }, {new:true},
function( err, result ) {
if ( err ) console.log( err);
console.log("after update: "+result.value.x);
res.end("success");
sem.leave();
}
);
});
});
})
});