还是上面那个例子,我们在定时器执行的同时,去读一个文件:
- const fs = require('fs')
- setInterval(() => {
- console.log(new Date().getTime())
- }, 3000)
-
- fs.readFile('./index.html', () => {})
线程数量变成了 11 个,这是因为在 Node 中有一些 IO 操作(DNS,FS)和一些 CPU 密集计算(Zlib,Crypto)会启用 Node 的线程池,而线程池默认大小为 4,因为线程数变成了 11。
我们可以手动更改线程池默认大小:
- process.env.UV_THREADPOOL_SIZE = 64
一行代码轻松把线程变成 71。
Libuv
Libuv 是一个跨平台的异步IO库,它结合了UNIX下的libev和Windows下的IOCP的特性,最早由Node的作者开发,专门为Node提供多平台下的异步IO支持。Libuv本身是由C++语言实现的,Node中的非苏塞IO以及事件循环的底层机制都是由libuv实现的。
libuv架构图
在Window环境下,libuv直接使用Windows的IOCP来实现异步IO。在非Windows环境下,libuv使用多线程来模拟异步IO。
注意下面我要说的话,Node的异步调用是由libuv来支持的,以上面的读取文件的例子,读文件实质的系统调用是由libuv来完成的,Node只是负责调用libuv的接口,等数据返回后再执行对应的回调方法。
Node.js 线程创建
直到 Node 10.5.0 的发布,官方才给出了一个实验性质的模块 worker_threads 给 Node 提供真正的多线程能力。
先看下简单的 demo:
- const {
- isMainThread,
- parentPort,
- workerData,
- threadId,
- MessageChannel,
- MessagePort,
- Worker
- } = require('worker_threads');
-
- function mainThread() {
- for (let i = 0; i < 5; i++) {
- const worker = new Worker(__filename, { workerData: i });
- worker.on('exit', code => { console.log(`main: worker stopped with exit code ${code}`); });
- worker.on('message', msg => {
- console.log(`main: receive ${msg}`);
- worker.postMessage(msg + 1);
- });
- }
- }
-
- function workerThread() {
- console.log(`worker: workerDate ${workerData}`);
- parentPort.on('message', msg => {
- console.log(`worker: receive ${msg}`);
- }),
- parentPort.postMessage(workerData);
- }
-
- if (isMainThread) {
- mainThread();
- } else {
- workerThread();
- }
上述代码在主线程中开启五个子线程,并且主线程向子线程发送简单的消息。
由于 worker_thread 目前仍然处于实验阶段,所以启动时需要增加 --experimental-worker flag,运行后观察活动监视器,开启了5个子线程
worker_thread 模块
worker_thread 核心代码(地址https://github.com/nodejs/nod...)
worker_thread 模块中有 4 个对象和 2 个类,可以自己去看上面的源码。
- isMainThread: 是否是主线程,源码中是通过 threadId === 0 进行判断的。
- MessagePort: 用于线程之间的通信,继承自 EventEmitter。
- MessageChannel: 用于创建异步、双向通信的通道实例。
- threadId: 线程 ID。
- Worker: 用于在主线程中创建子线程。第一个参数为 filename,表示子线程执行的入口。
- parentPort: 在 worker 线程里是表示父进程的 MessagePort 类型的对象,在主线程里为 null
- workerData: 用于在主进程中向子进程传递数据(data 副本)
总结
多进程 vs 多线程
对比一下多线程与多进程:
(编辑:ASP站长网)
|