nodejs线程和进程的理解

Nodejs是单线程

什么是线程

一个进程中可以有多个线程同时运行,称为多线程,一个线程可与同属一个进程的其它线程共享进程所拥有的全部资源,同一进程中的多个线程之间可以并发执行。

线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。

有时候,线程也称作轻量级进程。就象进程一样,线程在程序中是独立的、并发的执行路径,每个线程有它自己的堆栈、自己的程序计数器和自己的局部变量。但是,与分隔的进程相比,进程中的线程之间的隔离程度要小。它们共享内存、文件句柄和其它每个进程应有的状态。

阻塞和非阻塞,异步与同步

阻塞/非阻塞与异步/同步是两个不同的概念,同步不代表阻塞,但是阻塞肯定就是同步了。

举个现实生活中的例子,我去食堂打饭,我选择了A套餐,然后工作人员帮我去配餐,如果我就站在旁边,等待工作人员给我配餐,这种情况就称之为同步;若工作人员帮我配餐的同时,排在我后面的人就开始点餐,这样整个食堂的点餐服务并没有因为我在等待A套餐而停止,这种情况就称之为非阻塞。这个例子就简单说明了同步但非阻塞的情况。

再如果我在等待配餐的时候去买饮料,等听到叫号再回去拿套餐,此时我的饮料也已经买好,这样我在等待配餐的同时还执行了买饮料的任务,叫号就等于执行了回调,就是异步非阻塞了。

Nodejs是单线程异步非阻塞

线程是cpu调度的一个基本单位,一个cpu同时只能执行一个线程的任务,同样一个线程任务也只能在一个cpu上执行,所以如果你运行Node.js的机器是像i5,i7这样多核cpu,那么将无法充分利用多核cpu的性能来为Node.js服务。

下面是解决单线程对cpu密集型任务的阻塞问题:

Nodejs多进程cluster

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var cluster = require('cluster');//加载clustr模块
var numCPUs = require('os').cpus().length;//设定启动进程数为cpu个数
if (cluster.isMaster) {
for (var i = 0; i < numCPUs; i++) {
cluster.fork();//启动子进程,产生一个新的进程
}
} else {
var express = require('express');
var app = express();
var fibo = function fibo (n) {//定义斐波那契数组算法
return n > 1 ? fibo(n - 1) + fibo(n - 2) : 1;
}
app.get('/', function(req, res){
var n = fibo(~~req.query.n || 1);//接收参数
res.send(n.toString());
});
app.listen(8124, '0.0.0.0');
console.log('listen on 8124');
}

Nodejs多进程child_process

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import express from 'express';
import { spawn } from 'child_process';
const app = express();
const spawnWorker = (n, end) => {// 定义工作函数
const fibo = (m) => m > 1 ? fibo(m - 1) + fibo(m - 2) : 1;
end(fibo(n));
};
const spawnEnd = (result) => {// 定义工作函数结束的回调函数参数
console.log(result);
process.exit();
};
app.get('/', (req, res) => {
const n = ~~req.query.n || 1;
// 拼接-e后面的参数
const spawnCmd = `(${spawnWorker.toString()}(${n},${spawnEnd.toString()}));`;
console.log(spawnCmd);// 注意这个打印结果
const worker = spawn('node', ['-e', spawnCmd]);// 执行node -e "xxx"命令
let fiboRes = '';
worker.stdout.on('data', (data) => { // 接收工作函数的返回
fiboRes += data.toString();
});
worker.on('close', () => {// 将结果响应给客户端
res.send(fiboRes);
});
});
app.listen(8124);

ab压力测试:

1
ab -c 100 -n 100 http://0.0.0.0:8124/?n=35
如果您觉得受益了,欢迎打赏鼓励。