node.js:如何锁定/同步代码块?



让我们以简单的代码片段为例:

var express = require('express');
var app = express();
var counter = 0;
app.get('/', function (req, res) {
// LOCK
counter++;
// UNLOCK
res.send('hello world')
})

假设app.get(...)被调用了大量次,正如您可以理解的那样,我不希望counter++行由两个不同的线程同时执行。

因此,我想锁定这一行,只有一条线程可以访问这一行。我的问题是如何在节点.js中做到这一点?

我知道有一个锁定包:https://www.npmjs.com/package/locks,但我想知道是否有一种">本机"方式可以在没有外部库的情况下做到这一点。

我不希望两个不同的线程同时执行行计数器++

这在node中是不可能发生的.js只是常规的Javascript编码。

node.js是单线程和事件驱动的,因此一次只有一段Javascript代码可以访问该变量。 您不必担心多线程系统的典型抢占式并发问题。

也就是说,如果使用异步代码.js则 node 中仍可能存在并发问题,因为 node.js 异步模型将控制权返回给系统以处理下一个事件,并且异步回调会在某个未来事件上调用。 但是,并发问题是非先发制人的,因此您可以完全控制它们何时可能发生。

如果您在app.get()路由处理程序中向我们展示您的实际代码,那么我们可以更具体地建议您在那里是否存在并发问题。 而且,如果您这样做,我们可以就如何最好地处理这个问题提供建议。

线程池中的线程都是在后台运行的本机代码。 它们仅通过事件队列对事件进行排队来触发实际的Javascript运行。 因此,由于所有运行的 Javascript 都是通过事件队列序列化的,因此您一次只能运行一段 Javascript。 事件队列的基本方案是解释器运行一段Javascript,直到它将控制权返回给系统。 此时,解释器在事件队列中查找,如果有事件在等待,它会拉出该事件并调用与该事件关联的回调。 同时,如果有本机代码在后台运行,则在完成时,它会将事件添加到事件队列中。 在当前 Javascript 将控制权返回给系统之前,不会处理该事件,然后它可以从事件队列中获取下一个事件。 因此,正是这个事件队列序列化一次只运行一段 Javascript。

编辑:Nodejs现在确实有WorkerThreads,它启用了Javascript的单独线程,但是每个线程都有自己的堆和自己的变量,因此一个线程中的变量不能直接从另一个线程访问。 您可以配置两个 WorkerThreads 都可以访问的共享内存,但这不是直接变量,而是内存块,如果您想使用共享内存,那么您确实需要编写自己的同步方法以确保您以原子方式访问变量。 您在问题中显示的代码没有使用任何这些代码,因此对counter变量的访问已经是原子的,并且不能同时被任何其他 Javascript 访问,即使您使用的是 WorkerThreads。

如果阻塞线程,则不会执行所有请求都将在队列中。

在Node 中阻塞线程不是好的做法.js

var express = require('express');
var app = express();
var counter = 0;
const getPromise = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve('Done')
}, 100);
});
}
app.get('/', async (req, res) => {
const localCounter = counter++; 
// Use local counter for rest of operation so value won't vary
// LOCK: Use promise/callback 
await getPromise(); // Not locked but waiting for getPromise to finish
console.log(localCounter); // Same value before lock
res.send('hello world')
})

Node.js 是单线程的,这意味着运行应用的任何单个进程都不会像您预期的那样出现数据争用。事实上,对locks库的快速检查表明,他们使用布尔标志和Array对象系统来确定某些东西是否被锁定。

只有当您计划与多个进程共享数据时,才应该真正担心这一点。在这种情况下,你可以在这里使用这个堆栈溢出线程中的 Alan 的锁文件方法。

最新更新