15

Here is a simple program:

var express = require('express');

var app = express.createServer();

var count = 0;

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

app.listen(3000);

When I open it in two different browsers, the first displays 0 and the second displays 1.

Why? They are different sessions so I expect node.js use different child processes for them. My understanding, with PHP, is that sharing variables should be implemented using databases.

Why can node.js do this without any external storage? Is it a single-process but multiple threads?

How do I declare a variable that belongs to a specific session?

Jeremy
  • 1
  • 85
  • 340
  • 366
Lai Yu-Hsuan
  • 27,509
  • 28
  • 97
  • 164

4 Answers4

15

Node.js is single process.

Your code runs in a single process ontop of an eventloop.

JavaScript is single threaded. Every piece of code you run is single threaded. Node.js is fast and scales because it does not block on IO (IO is the bottle neck).

Basically any javascript you run is single threaded. JavaScript is inherantly single threaded.

When you call parts of the nodeJS API it uses threading internally on the C++ level to make sure it can send you the incoming requests for the HTTP servers or send you back the files for the file access. This enables you to use asynchronous IO

As for 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++;
});
Raynos
  • 166,823
  • 56
  • 351
  • 396
  • 2
    Uh... Every piece of code is single threaded, but uses multi threading internally? What does you mean? – Lai Yu-Hsuan Jun 15 '11 at 14:05
  • 1
    @LaiYu-Hsuan JavaScript is single threaded. The nodeJS library is part C++, part javascript. The underlying C++ code that node runs on is multi threaded. – Raynos Jun 15 '11 at 14:09
15

The 'problem' you're seeing isn't specific to node. It's just a function of scoping in javascript. You've declared your variable under a scope that lives for the lifetime of the server, not the request.

Declaring your variable within the function used to respond to your route will solve your problem:

var express = require('express');

var app = express.createServer();

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

app.listen(3000);
MateodelNorte
  • 1,282
  • 11
  • 21
  • Just a question: the count variable defining as in the question is thread safe? Even though javascript is single thread environment, worker threads can modify the count? – Erdal76t Apr 09 '20 at 12:31
  • Threads in Node.js aren't magic. Only the main, single threaded process has access to the variable above. Worker threads have a special means of communicating shared memory: https://nodejs.org/api/worker_threads.html – MateodelNorte Apr 09 '20 at 16:15
  • Even if single threaded process has access to the count variable. Wouldn't it be unsafe due to count++ operation (read-modify-write). After a session read the count, the others can modify the count? – Erdal76t Apr 10 '20 at 12:28
  • 1
    This route will literally never saying anything but '0'. The count variable lives in the request function scope and will be discarded as soon as the function is done running. – MateodelNorte Apr 10 '20 at 16:04
3

node.js is essentially single-threaded, actually.

Each request to a PHP script is handled by a separate PHP instance, but it executes within the same server process (often Apache).

A node.js script is both the server and the handler in one. Since the state is held by the server, it is preserved between requests. For long-term persistence you would want to use a database as in PHP. However, if you want to implement a chat server or something where long-term memory isn't important, keeping it all in the server's memory can simplify things.

Jeremy
  • 1
  • 85
  • 340
  • 366
  • It simplify things. But how about race condition? Though they share the variables and there is no "mutex", how am I sure that two user can't write wrong values? Or, in this case, I should use database? – Lai Yu-Hsuan Jun 15 '11 at 14:14
  • 1
    Race conditions are rarer in a single-threaded model like Node.js uses: Because only one code path can run at a time, you can't run into classical race-condition problems like two threads attempting to update a variable at the same time. If you need verified atomicity of changes, though, you should still defer to a database. – 00dani Apr 11 '13 at 05:14
  • I think that In that case count++ operation (by read-modify-write) comes out race conditions. Even Javascript has just one thread, when one sessions modify the count variable, the other one can write the count variable. – Erdal76t Apr 11 '20 at 12:56
0

Node.js is single threaded, which can reduce the overhead of child process/thread creation. And it takes use of asyn functions and callbacks, so that Node can handle other requests when the previous one is blocked, and provides good performance when the app focuses on heavy data traffic but not computation.

It is a little bit like the concept of functional programming, you need to handle variable carefully.
You should use closure to create a space for each request if you wanted. But keep in mind that closure cannot be optimized by JS engine easily.

Oscar
  • 59
  • 5