代码之家  ›  专栏  ›  技术社区  ›  CrazySynthax

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

  •  2
  • CrazySynthax  · 技术社区  · 6 年前

    让我们来看看简单的代码片段:

    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 但是我想知道 本地的 “没有外部库的方式。

    3 回复  |  直到 6 年前
        1
  •  3
  •   jfriend00    6 年前

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

    这在node.js中不可能发生。

    node.js是单线程和事件驱动的,所以一次只运行一段javascript代码。您不必担心多线程系统的典型先发制人并发问题。

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

    如果您在 app.get() 路由处理程序,然后我们可以更具体地建议您是否存在并发问题。如果你这样做了,我们可以就如何最好地处理这个问题提出建议。

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

        2
  •  1
  •   Andres Salgado    6 年前

    node.js是单线程的,这意味着运行应用程序的任何单个进程都不会像您预期的那样有数据竞争。事实上,快速检查 locks 库显示它们使用一个布尔标志和一个 Array 对象来确定某个对象是否被锁定。

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

        3
  •  0
  •   Rahul Sharma    6 年前

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

    在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')
    })