The following 10 interview questions will help you better understand the processes and threads of Node.js

About the author: May Jun, Nodejs Developer, love technology, like to share the 90’s youth, public account “Nodejs technology Stack”, Github open source project www.nodejs.red

Quick navigation

  • What are processes and threads? The difference between the two? Reference: Interview1
  • What is an orphan process? Reference: Interview2
  • When you create multiple processes, it’s in the codeapp.listen(port)Why is no port reported to be occupied when the fork is performed? Reference:Interview3
  • What is IPC communication and how is it established? In what scenarios do I need to use IPC? Reference: Interview4
  • Is Node.js single-threaded or multi-threaded? Why single threaded? Reference: Interview5
  • What, why, and how to write daemons? Reference: Interview6
  • Implement a simple command line interactive program? Reference: Interview7
  • How to make a JS file an executable command program in Linux? Reference: Interview8
  • What is the current working directory of the process? What does it do? Reference: Interview9
  • State sharing between multiple processes or Web services? Reference: Interview10

About the author: May Jun, Nodejs Developer, love technology, like to share the 90’s youth, public account “Nodejs technology Stack”, Github open source project www.nodejs.red

Interview1

What are processes and threads? The difference between the two?

Thread and process is a very basic concept of server. After introducing the concept of process and thread in the advanced Process and Thread of Node.js, the actual application of process and thread in Node.js is given. For this piece of advice that is not quite understood, let’s take a look.

Interview2

What is an orphan process?

After the parent process creates the child process, the parent process exits, but one or more child processes corresponding to the parent process are still running, these child processes will be adopted by the system init process, the corresponding process PPID is 1, this is the orphan process. Use the following code example to illustrate this.

// master.js
const fork = require('child_process').fork;
const server = require('net').createServer();
server.listen(3000);
const worker = fork('worker.js');

worker.send('server', server);
console.log('worker process created, pid: %s ppid: %s', worker.pid, process.pid);
process.exit(0); // After the child process is created, the main process exits, and the created worker process will become an orphan process
Copy the code
// worker.js
const http = require('http');
const server = http.createServer((req, res) = > {
	res.end('I am worker, pid: ' + process.pid + ', ppid: ' + process.ppid); // Record the pid of the current worker process and ppID of the parent process
});

let worker;
process.on('message'.function (message, sendHandle) {
	if (message === 'server') {
		worker = sendHandle;
		worker.on('connection'.function(socket) {
			server.emit('connection', socket); }); }});Copy the code

Orphan process example source code

The console tests, output the current worker process PID and the parent process PPID

$ node master
worker process created, pid: 32971 ppid: 32970
Copy the code

Since the parent process exits in master.js, only the worker process is displayed on the activity monitor.

Again, open the console call interface and you can see that worker process 32971 has ppID 1 (init process) and is now an orphan process

$curl http://127.0.0.1:3000 I am worker, pid: 32971, ppID: 1Copy the code

Interview3

When creating a multiprocess, the code has app.Listen (port) in the fork, why does it not report that the port is occupied?

Check whether the port is occupied

// master.js
const fork = require('child_process').fork;
const cpus = require('os').cpus();

for (let i=0; i<cpus.length; i++) {
    const worker = fork('worker.js');
    console.log('worker process created, pid: %s ppid: %s', worker.pid, process.pid);
}
Copy the code
//worker.js
const http = require('http');
http.createServer((req, res) = > {
	res.end('I am worker, pid: ' + process.pid + ', ppid: ' + process.ppid);
}).listen(3000);
Copy the code

Multi-process port occupancy conflict example source code

In the above code example, the console executes node master.js. Only one worker can listen to port 3000. The rest will throw Error: Listen EADDRINUSE :::3000

So how to implement multi-port listening in multi-process mode? After v0.5.9, Node.js supports sending handles between processes. How to send handles? As follows:

/** * http://nodejs.cn/api/child_process.html#child_process_subprocess_send_message_sendhandle_options_callback * message * sendHandle */
subprocess.send(message, sendHandle)
Copy the code

After the IPC channel is established between the parent and child processes, messages are sent through the send method of the child process object. The second parameter sendHandle is the handle, which can be TCP socket, TCP server, UDP socket, etc. To solve the problem of multi-process port usage. We pass the main process socket to the child process and modify the code to look like this:

//master.js
const fork = require('child_process').fork;
const cpus = require('os').cpus();
const server = require('net').createServer();
server.listen(3000);
process.title = 'node-master'

for (let i=0; i<cpus.length; i++) {
    const worker = fork('worker.js');
    worker.send('server', server);
    console.log('worker process created, pid: %s ppid: %s', worker.pid, process.pid);
}
Copy the code
// worker.js
const http = require('http');
http.createServer((req, res) = > {
	res.end('I am worker, pid: ' + process.pid + ', ppid: ' + process.ppid);
})

let worker;
process.title = 'node-worker'
process.on('message'.function (message, sendHandle) {
	if (message === 'server') {
		worker = sendHandle;
		worker.on('connection'.function(socket) {
			server.emit('connection', socket); }); }});Copy the code

Handle transfer to solve the problem of multi-process port occupation conflict example source code

After verification, the console executes node master.js and the following results are expected. The multi-process port usage problem has been resolved.

$ node master.js
worker process created, pid: 34512 ppid: 34511
worker process created, pid: 34513 ppid: 34511
worker process created, pid: 34514 ppid: 34511
worker process created, pid: 34515 ppid: 34511
Copy the code

Regarding the multi-process port occupation problem, cNode has an article which can also look at the main functions of the cluster module in Node.js through source code parsing

Interview4

What is IPC communication and how is it established? In what scenarios do I need to use IPC?

Inter-process communication (IPC) is the inter-process communication technology. Since each process has its own independent address space after creation, the purpose of implementing IPC is to share and access resources between processes. There are various ways to implement IPC: Pipes, message queues, semaphores, Domain sockets, node.js is implemented using pipes.

Take a look at the Demo, where IPC is not used

// pipe.js
const spawn = require('child_process').spawn;
const child = spawn('node'['worker.js'])
console.log(process.pid, child.pid); // Main process ID3243 child process 3244
Copy the code
// worker.js
console.log('I am worker, PID: ', process.pid);
Copy the code

The console executes node peped.js and outputs the main process ID and child process ID, but the child process worker.js information is not printed in the console because the newly created child process has its own stdio stream.

$ node pipe.js
41948 41949
Copy the code

Create an IPC channel to pass messages between the parent and child processes to achieve output information

Modify pipe.js to create a pipe link between the stdio of the child process and the stdio of the current process. You can also create an IPC mechanism through the stdio option of the spawn() method, see options.stdio

// pipe.js
const spawn = require('child_process').spawn;
const child = spawn('node'['worker.js'])
child.stdout.pipe(process.stdout);
console.log(process.pid, child.pid);
Copy the code

Parent process IPC communication source sample

Once again, the console executes node pipe.js and the worker.js information is printed

$ 42473 42474
I am worker, PID:  42474
Copy the code

How do the parent and child processes communicate?

Before creating a child process, the parent process will first create an IPC channel and listen to it. After that, the parent process will create the child process and pass the file descriptor of the IPC channel to the child process by means of the environment variable (NODE_CHANNEL_FD). When the child process starts, it links the IPC channel according to the file descriptor passed, thus establishing the communication mechanism between the father and child process.

Parent-child IPC communication interaction diagram

Interview5

Is Node.js single-threaded or multi-threaded? Why single threaded?

First question, is Node.js single-threaded or multi-threaded? Javascript is single-threaded, but Node.js, which runs on the server, is not.

Second question, why is Javascript single-threaded? This problem needs to start with the browser. If multiple threads operate on the same DOM in the browser environment, it will be messy. That means that operations on the DOM can only be single-threaded to avoid DOM rendering conflicts. In a browser environment, the UI rendering thread and the JS execution engine are mutually exclusive, with each causing the other to be suspended during execution, as determined by the JS engine.

Interview6

What, why, and how to write daemons?

Daemons run in the background and are not affected by the terminal. What does that mean? If you are familiar with node.js development, when you open a terminal and run Node app.js to start a service process, the terminal will be occupied all the time. If you close the terminal, the service will be broken, which is the foreground operation mode. If I run node app.js to start a service process on this terminal, I can do other things on this terminal without any interaction.

Create a step

  1. Create a child process
  2. Create a new session in a child process (call system function setsid)
  3. Change the child process working directory (e.g., “/” or “/usr/etc.)
  4. Parent process termination

Node.js demonstrates how to write a daemon process Demo

The processing logic in the index.js file completes the first step above by creating the child process with spawn. Set options.detached to true to keep the child running after the parent exits (the system layer calls the setSID method). See options_detached for the second step. Options. CWD Specifies the working directory of the current child process. If you do not do this, the current working directory will be inherited by default. This is the third step. Run daemon.unref() to exit the parent process, see options.stdio for the fourth step.

// index.js
const spawn = require('child_process').spawn;

function startDaemon() {
    const daemon = spawn('node'['daemon.js'] and {cwd: '/usr'.detached : true.stdio: 'ignore'});console.log('daemon start parent pid: %s, daemon pid: %s', process.pid, daemon.pid);
    daemon.unref();
}

startDaemon()
Copy the code

The processing logic in the daemon.js file starts a timer every 10 seconds so that the resource does not exit and logs are written to the child process’s current working directory

// /usr/daemon.js
const fs = require('fs');
const { Console } = require('console');

// custom simple logger
const logger = new Console(fs.createWriteStream('./stdout.log'), fs.createWriteStream('./stderr.log'));

setInterval(function() {
	logger.log('daemon pid: ', process.pid, ', ppid: ', process.ppid);
}, 1000 * 10);
Copy the code

The daemon implements the source address of the Node.js version

Run the test

Js daemon process starts the parent process PID: 47608, and the daemon process PID: 47609Copy the code

Open the activity monitor to see that there is currently only one process 47609, and this is the process we need to daemon

Daemons read recommendations

  • Daemon implementation (node.js version)
  • Daemon implementation (C version)

Daemon Summary

In the actual work of the daemon process is not unfamiliar, such as PM2, egg-cluster, etc., the above is just a simple Demo of the daemon process to do a description, in the actual work of the robustness of the daemon process is still very high requirements, for example: The monitoring of process exceptions, the scheduling of worker processes, the restart of processes after a crash, and so on, need to be constantly thought about.

Interview7

Use the spawn method of child process child_process, as shown below:

const spawn = require('child_process').spawn;
const child = spawn('echo'["Simple command line interaction"]);
child.stdout.pipe(process.stdout); // Print the output of the child process as input to the current process
Copy the code
$Node execFile Simple command-line interactionCopy the code

Interview8

How to make a JS file an executable command program in Linux?

  1. Create a new hello.js file with the header#! /usr/bin/env node, which indicates that the current script is parsed using Node.js
  2. Grant executable permission to the file chmod +x chmod +x /${dir}/hello.js, the directory is customized
  3. Create a soft link file in /usr/local/binsudo ln -s /${dir}/hello.js /usr/local/bin/helloThe filename is the name we use on the terminal
  4. A terminal executing hello is equivalent to entering node hello.js
#! /usr/bin/env node

console.log('hello world! ');
Copy the code

Terminal test

$ hello
hello world!
Copy the code

Interview9

What is the current working directory of the process? What does it do?

The current working directory of the process can be obtained by using the process.cwd() command. By default, it is the directory where the process started. If a child process is created, it inherits from the parent process, and can be reset using the process.chdir() command. For example, you can specify the CWD option to set the working directory of the child process created using the spawn command.

What does it do? For example, if you read a file through fs, if you set it to a relative path, you will look it up relative to the directory where the current process started, so you will not get the correct result if the startup directory is set incorrectly. There is also a case in which a reference to a third party module is also based on the directory where the current process started.

/ / sample
process.chdir('/Users/may/Documents/test/') // Set the current process directory

console.log(process.cwd()); // Get the current process directory
Copy the code

Interview10

State sharing between multiple processes or Web services?

In multi-process mode, each process is independent of each other. For example, if the user logs in, the session will be saved in the server process. If I have 4 worker processes, each process will save a copy. The same is true for multiple Web services, and it’s going to happen that I created A Session on machine A, and I’m going to create another Session after the load balance is distributed to machine B. The common practice is to share data through Redis or databases.

Starting from mu class network, www.imooc.com/article/288…