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

时间:2018-06-22 05:32:08

标签: 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++行由两个不同的线程同时执行。

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

我知道有一个锁包:https://www.npmjs.com/package/locks,但是我想知道是否有没有外部库的“ native ”方法。

4 个答案:

答案 0 :(得分:3)

  

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

这不能在node.js中发生。

node.js是单线程的,并且是事件驱动的,因此一次只能运行一个Javascript代码。您不必担心多线程系统中典型的抢先式并发问题。

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

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

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

答案 1 :(得分:1)

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

只有计划与多个进程共享数据时,才应该真正担心这一点。在这种情况下,您可以使用this stackoverflow thread here中的Alan的锁定文件方法。

答案 2 :(得分:0)

Node js是单线程的,但是您可以通过Promise的概念

实现
var express = require('express');
var app = express();
var counter = 0;

app.get('/', function(req, res) {
  // LOCK
  async function f() {
    console.log(counter++);
    return;
  }
  // UNLOCK
  f().then(res.send('hello world'));

})

app.listen(5000, () => console.log('Example app listening on port 5000!'))

答案 3 :(得分:0)

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

在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')
})
相关问题