信号量等同于Node js,variables在并发请求中被修改?

我在过去的一个星期面对这个问题,我只是对此感到困惑。 保持简短的解释问题。

我们有一个内存模型,它存储像预算等值。现在,当一个API的调用它有一个与其相关联的花费。

然后,我们检查内存模型,并将花费添加到现有的花费,然后检查预算,如果超过,我们不会再接受该模型的更多点击。 对于每个调用,我们也使用db,但这是一个asynchronous操作。

一个简短的例子

api.get('/clk/:spent/:id', function(req, res) { checkbudget(spent, id); } checkbudget(spent, id){ var obj = in memory model[id] obj.spent+= spent; obj.spent > obj.budjet // if greater. obj.status = 11 // 11 is the stopped status update db and rebuild model. } 

这用于工作正常,但现在与并发请求我们得到错误的花费增加超过预算,并在一段时间后停止。 我们用j米模拟了这个电话,发现了这个。

就我们所能看到的,当状态更新到11时,节点是asynchronous的,许multithreading已经更新了活动的花费。

如何为Node.js提供信号量逻辑,以便可变预算与模型同步

更新

  db.addSpend(campaignId, spent, function(err, data) { campaign.spent += spent; var totalSpent = (+camp.spent) + (+camp.cpb); if (totalSpent > camp.budget) { logger.info('Stopping it..'); camp.status = 11; // in-memory stop var History = []; History.push(some data); db.stopCamp(campId, function(err, data) { if (err) { logger.error('Error while stopping ); } model.campMAP = buildCatMap(model); model.campKeyMap = buildKeyMap(model); db.campEventHistory(cpcHistory, false, function(err) { if (err) { logger.error(Error); } }) }); } }); 

代码的GIST现在可以请任何人帮忙

问: NodeJs是否存在semaphore或等价NodeJs

答: 不。

问:那么NodeJs用户如何处理竞争条件呢?

答:理论上你不应该这样做,因为在javascript没有thread

在深入研究我提出的解决scheme之前,我认为了解NodeJs是如何工作是非常重要的。

对于NodeJs它由基于事件的体系结构驱动。 这意味着在Node进程中有一个包含所有“待办事项”事件的事件队列。

event从队列中popnode将执行所有必需的代码,直到完成。 在运行过程中进行的任何async调用都会作为其他events生成,并在event queue中排队等待,直到听到响应,然后再次运行它们。

问:那么我该怎么做才能确保一次只有一个请求可以对数据库执行updates

答:我相信有很多方法可以达到这个目标,但更简单的方法之一就是使用set_timeout API。

例:

 api.get('/clk/:spent/:id', function(req, res) { var data = { id: id spending: spent } canProceed(data, /*functions to exec after canProceed=*/ checkbudget); } var canProceed = function(data, next) { var model = in memory model[id]; if (model.is_updating) { set_timeout(isUpdating(data, next), /*try again in=*/1000/*milliseconds*/); } else { // lock is released. Proceed. next(data.spending, data.id) } } checkbudget(spent, id){ var obj = in memory model[id] obj.is_updating = true; // Lock this model obj.spent+= spent; obj.spent > obj.budjet // if greater. obj.status = 11 // 11 is the stopped status update db and rebuild model. obj.is_updating = false; // Unlock the model } 

注意:我在这里得到的是伪代码,所以你可能需要调整一下。

这里的想法是在你的模型中有一个标志来指示一个HTTP request是否可以继续执行关键的代码path。 在这种情况下,您的checkbudgetfunction和超越。

当一个请求进来时,它检查is_updating标志,看它是否可以继续。 如果它是true那么它调度一个事件,在稍后被解雇,这个“setTimeout”基本上成为一个事件,并被放置到node的事件队列中以供后续处理

当这个事件被解雇后,再次检查。 发生这种情况,直到is_update标志变为false然后请求继续执行它的操作,并且当所有关键代码完成时, is_update再次被设置为false。

不是最有效的方式,但它完成了工作,当性能成为问题时,您总是可以重新访问解决scheme。