在Ubuntu系统中,Node.js并发处理可采用异步编程、工作线程、集群模块或第三方库。异步编程适合I/O密集型任务,利用事件循环;工作线程处理CPU密集型计算,避免主线程阻塞;集群模块实现多进程负载均衡,用于高并发HTTP服务;第三方库简化复杂并发逻辑。
在Ubuntu上折腾Node.js并发处理,其实有不少路子可走。不少人一上来就盯着多线程、多进程,但Node.js的异步机制本身才是它的灵魂。下面把这几种主流方式捋一遍,顺便聊聊各自适合什么场景。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
Node.js最核心的设计就是异步I/O,能用非阻塞的方式处理大量并发请求。实现手段无非回调、Promise、async/await。现在大部分人都习惯async/await的写法,可读性高,代码也更清爽。
const fs = require('fs').promises;
async function readFiles() {
try {
const file1 = await fs.readFile('file1.txt', 'utf-8');
const file2 = await fs.readFile('file2.txt', 'utf-8');
console.log(file1, file2);
} catch (error) {
console.error(error);
}
}
readFiles();
这种模式特别适合文件读写、数据库查询、网络请求这类I/O密集型任务。只要操作本身不阻塞事件循环,并发能力就上来了。
当遇到CPU密集型任务(比如大量计算、图像处理、加密解密)时,光靠异步就不够用了。Node.js 10.5+ 引入了worker_threads模块,允许你在独立线程里跑Ja vaScript代码,真正利用多核CPU。
const { Worker } = require('worker_threads');
function runWorker(workerData) {
return new Promise((resolve, reject) => {
const worker = new Worker('./worker.js', { workerData });
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) {
reject(new Error(`Worker stopped with exit code ${code}`));
}
});
});
}
runWorker('Hello from main thread')
.then(result => console.log(result))
.catch(error => console.error(error));
在worker.js里这么写:
const { parentPort } = require('worker_threads');
parentPort.on('message', (message) => {
console.log(`Message from main thread: ${message}`);
parentPort.postMessage('Hello from worker thread');
});
注意:worker之间不共享内存(要靠消息传递),做并行计算时要权衡数据序列化的开销。
如果要做HTTP服务,想充分利用多核CPU,cluster模块是最经典的方案。主进程负责调度,子进程共享同一个端口,各自处理请求。
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
// Fork workers.
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
});
} else {
// Workers can share any TCP connection
http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
console.log(`Worker ${process.pid} started`);
}
每个子进程都是独立的Node.js实例,互不影响。如果某个worker挂掉,主进程可以重新fork一个,提升了稳定性。
社区里还有不少优秀的库,比如async、bluebird、p-limit等。它们封装了并行执行、限流、重试、超时等实用功能。如果你的需求比较复杂,直接用现成的库能省去不少重复造轮子的时间。
说到底,选哪种方式取决于你的任务类型:
没有银弹,理解每种方案的优缺点再下手,才能写出既高效又可控的并发代码。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述