有在写 node 的人可能听人提过, node 的底层是一个支援非同步 IO 的 threadpool , 而有读过我前三篇的读者应该可以联想到 epoll 和 IOCP 两种非同步 IO model 的现象, 就是创建一群闲置的 thread , 每当有一个 IO 发生就唤醒一个新的 thread 来运行。如果 threadpool 每个 thread 都在使用中, 就先让 IO 事件排好队等着。我们今天就试着让 node 呈现这种现象。
实验步骤
用 express 写了一下 API
import express = require('express');
const router = express.Router();
router.get('/', (req: express.Request, res: express.Response) => {
// Disable caching for content files
res.header('Cache-Control', 'no-cache, no-store, must-revalidate');
res.header('Pragma', 'no-cache');
res.header('Expires', '0');
res.render('index', { title: 'Express' });
});
export default router;
再写一个没有功能但有大量内容的前端页面
extends layout
block content
h1= title
p Welcome to #{title}
h1= title
p Welcome to #{title}
h1= title
p Welcome to #{title}
h1= title
p Welcome to #{title}
h1= title
p Welcome to #{title}
h1= title
p Welcome to #{title}
h1= title
p Welcome to #{title}
h1= title
p Welcome to #{title}
h1= title
// 往下延伸 5000 行
再写一个 node 应用, 呼叫 API
const fetch = require('node-fetch');
for (let i = 0; i < 50; i++)
fetch('http://127.0.0.1:1337/', { method: 'GET' }).then((res) => {
if (res.status == 200) {
const time = new Date();
console.log('success : ' + time);
} else {
const time = new Date();
console.log('error : ' + time);
}
});
次数设定成同时呼叫 50 次
可以看到这两个应用程序的 process 正在运行。
观察 API server 的 thread 状态
API 被呼叫前
API 正在运作时
可以理解为 thread 31612 是 main thread
其他 4 条是帮助他完成任务的 threadpool
而 threadpool 在这里做的就是读取网页页面与进行渲染, main thread 做的是进行 network IO
可以发现由 main thread 发出 IO 後, 就只有 main Thread 在等待回传, threadpool 基本都在闲置
router.get(
'/',
(req: express.Request, res: express.Response, next: express.NextFunction) => {
console.log('In');
next();
},
(req: express.Request, res: express.Response) => {
setTimeout(() => {
// Disable caching for content files
console.log(new Date());
res.header('Cache-Control', 'no-cache, no-store, must-revalidate');
res.header('Pragma', 'no-cache');
res.header('Expires', '0');
res.render('index', { title: 'Express' });
}, 5000);
}
);
结果是
所以总共只有停下来等待了 5 秒钟, 因为 Network IO 会被 main thread 掌管, 其没有数量限制的疯狂切换, 以近乎同时的方法处理所有 IO , 而本地资料抓取与渲染, 会被 TP 一个一个处理, 处理完再交给 main thread 回传。而 TP 的数量是 4 个 thread
这个现象就像我昨天写的 IOCP httpServer , main thread 疯狂的接收 Network IO , 和把 NetWork IO 的事件放入 eventQueue, thread pool 一个一个醒来, 各取一个事件处理与回传。
当然两件事还是有蛮大的差别, 千万别觉得他们差不多。(ex: node 的回传会丢回来给 main thread 传, node 的事件拆分没有那麽粗糙, 所以可以做到更细致的事件切换 ,.......)
实验就到这里, 基本上可以利用 epoll 或 IOCP 这类演算法来解释, 但实际上 node 底层更为复杂, 就让我们继续看下面的附注吧
https://stackoverflow.com/questions/63369876/nodejs-what-is-maximum-thread-that-can-run-same-time-as-thread-pool-size-is-fo
懒人包 :
因为这个现象, 有些人在撰写 micro service 中具有大量 IO 的微服务时, 会试着提高 node 的 thread 数量。但这篇文章说, 网路 IO 都在 main thread 完成, 所以提高 node 的 thread 数量没啥用。
Node 的非同步不是单纯的非同步 IO , 而是所有可以非同步的事件被分成两大类, 一类是只能在 main thread 内进行, 但 main thread 却会在自己一条 thread 内快速切换任务完成所有事情, 举例就是 network IO , 另一种就是会唤醒沉睡的 thread ( in threadpool ) 且要求他们执行 (但其实这类事件不全是 IO , 但为了方便之後还是统一称为 IO ) , 像是本地档案读写。
简单看看一个用 JS 撰写的 model 如何调用底层的 C++
明天见 !
<<: [拯救上班族的 Chrome 扩充套件] 规划架构和使用情境
>>: JavaScript学习日记 : Day6 - 函数(一)
学习资源整理-资安社团 决定好要学习哪个面向,那要去哪里学呢??是不是要花大钱去补习才能学得会呢? ...
讲到硬体就会用到权限控制,然後一定会用onActivityResult和startActivityF...
Modules: struct UserInfoResponse: Decodable { var ...
Day 19 - Socket 连线 昨天我们讲解了如何让我们能在程序内切换分页,今天我们就换个口味...
第二十二天 各位点进来的朋友,你们好阿 小的不才只能做这个系列的文章,但还是希望分享给点进来的朋友,...