【问题标题】:Why do different node.js sessions share variables?为什么不同的 node.js 会话共享变量?
【发布时间】:2013-02-18 16:46:01
【问题描述】:

这是一个简单的程序:

var express = require('express');

var app = express.createServer();

var count = 0;

app.get("/", function(req, res) {
    res.send(count.toString());
    count++;
});

app.listen(3000);

当我在两个不同的浏览器中打开它时,第一个显示0,第二个显示1

为什么?它们是不同的会话,所以我希望 node.js 为它们使用不同的子进程。我对 PHP 的理解是共享变量应该使用数据库来实现。

为什么 node.js 可以在没有任何外部存储的情况下做到这一点?是单进程多线程吗?

如何声明属于特定会话的变量?

【问题讨论】:

    标签: node.js express


    【解决方案1】:

    Node.js 是单进程。

    您的代码在事件循环之上的单个进程中运行。

    JavaScript 是单线程的。您运行的每一段代码都是单线程的。 Node.js 速度快且可扩展,因为它不会阻塞 IO(IO 是瓶颈)。

    基本上,您运行的任何 javascript 都是单线程的。 JavaScript 天生就是单线程的。

    当您调用部分 nodeJS API 时,它会在 C++ 级别内部使用线程,以确保它可以向您发送 HTTP 服务器的传入请求或向您发送回文件以进行文件访问。这使您可以使用异步 IO

    至于sessions

    app.use(express.session({ secret: "Some _proper_ secret" }));
    ...
    app.get("/", function(req, res) {
        if (req.session.count == null) {
            req.session.count = 0;
        }
        res.send(req.session.count);
        req.session.count++;
    });
    

    【讨论】:

    • 呃...每段代码都是单线程的,但内部使用的是多线程?什么意思?
    • @LaiYu-Hsuan JavaScript 是单线程的。 nodeJS 库部分是 C++,部分是 javascript。节点运行的底层 C++ 代码是多线程的。
    【解决方案2】:

    您看到的“问题”并非特定于节点。它只是 javascript 中的作用域功能。您已经在服务器生命周期而不是请求的范围内声明了变量。

    在用于响应路由的函数中声明变量将解决您的问题:

    var express = require('express');
    
    var app = express.createServer();
    
    app.get("/", function(req, res) {
        var count = 0;
        res.send(count.toString());
        count++;
    });
    
    app.listen(3000);
    

    【讨论】:

    • 只是一个问题:问题中定义的计数变量是线程安全的吗?即使javascript是单线程环境,worker线程也可以修改count?
    • Node.js 中的线程并不神奇。只有主单线程进程可以访问上面的变量。工作线程有一种特殊的共享内存通信方式:nodejs.org/api/worker_threads.html
    • 即使单线程进程可以访问计数变量。由于 count++ 操作(读取-修改-写入),它会不会不安全。一个会话读取计数后,其他人可以修改计数吗?
    • 这条路线只会说'0'。 count 变量存在于请求函数的作用域中,一旦函数运行完毕就会被丢弃。
    【解决方案3】:

    node.js 实际上是单线程的。

    对 PHP 脚本的每个请求都由一个单独的 PHP 实例处理,但它在同一个服务器进程(通常是 Apache)中执行。

    node.js 脚本既是服务器又是处理程序。由于状态由服务器保存,因此在请求之间保留。对于长期持久性,您可能希望使用 PHP 中的数据库。但是,如果您想实现聊天服务器或长期记忆不重要的东西,将其全部保存在服务器的内存中可以简化事情。

    【讨论】:

    • 它简化了事情。但是比赛条件呢?尽管他们共享变量并且没有“互斥锁”,但我如何确定两个用户不能写入错误的值?或者,在这种情况下,我应该使用数据库?
    • 竞争条件在 Node.js 使用的单线程模型中比较少见:因为一次只能运行一个代码路径,所以您不会遇到像两个线程尝试这样的经典竞争条件问题同时更新一个变量。但是,如果您需要验证更改的原子性,您仍应遵循数据库。
    • 我认为在这种情况下 count++ 操作(通过读取-修改-写入)会出现竞争条件。甚至Javascript只有一个线程,当一个会话修改计数变量时,另一个会话可以写入计数变量。
    【解决方案4】:

    Node.js 是单线程的,可以减少子进程/线程创建的开销。并且它使用了异步函数和回调,这样Node可以在前一个请求被阻塞时处理其他请求,并且在应用程序专注于大数据流量而不是计算时提供良好的性能。

    有点像函数式编程的概念,需要小心处理变量。
    如果需要,您应该使用闭包为每个请求创建一个空间。但请记住,JS 引擎无法轻松优化闭包。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-06
      • 1970-01-01
      • 2016-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多