piscina 库是一个 Node.js Worker Thread Pool,进行了一些调研。
一些特性
piscina 会优先使用当前负载最小的实例,所以如果有 10 个零负载的 thread,那么一下调用 10 次 runTask 可以保证每个 thread 都接收到一次。
piscina 支持 thread 的异步初始化,使用方式:
1 2 3 4 5 6
| async function initialize() { await someAsyncInitializationActivity(); return ({ a, b }) => a + b; }
module.exports = initialize();
|
执行 new Piscina()
时默认不会创建 thread,会按需在调用 runTask 时创建 thread。但可以通过设置 minThreads 来使得 new Piscina()
时就创建一定数量的 thread。
运行中 thread 创建
调用 runTask 时,遇到以下两种情况,会尝试创建新的 thread:
- 等待队列中有正在等待的任务(表示所有 thread 都在忙碌),并且当前 thread 数量没有超过 maxThreads。
- 没找到可用的 thread,并且当前 thread 数量没有超过 maxThreads。
创建过程中的 thread 是不可用的,会 piscina 会等待这个 thread 异步初始化,初始化完成之后才进行使用:
1 2 3 4 5 6 7 8 9 10 11 12
| worker.on('message', (message : ReadyMessage) => { if (message.ready === true) { if (workerInfo.currentUsage() === 0) { workerInfo.unref(); }
if (!workerInfo.isReady()) { workerInfo.markAsReady(); } return; } });
|
调度方式
寻找当前负载最小的实例:
1 2 3 4 5 6 7 8 9 10 11 12 13
| findAvailable () : T | null { let minUsage = this.maximumUsage; let candidate = null; for (const item of this.readyItems) { const usage = item.currentUsage(); if (usage === 0) return item; if (usage < minUsage) { candidate = item; minUsage = usage; } } return candidate; }
|
预热 demo
我写了一个预热 piscina 的 demo:https://github.com/meixg/piscina-warmup-demo。
预热前:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| threadId: 1 done: 0th at 20.103199999779463 threadId: 2 done: 0th at 26.904699999839067 threadId: 3 done: 0th at 26.526700001209974 threadId: 5 done: 0th at 29.538399998098612 threadId: 4 done: 0th at 28.85249999910593 threadId: 6 done: 0th at 28.910900000482798 threadId: 3 done: 100th at 0.0568000003695488 threadId: 7 done: 0th at 13.932300001382828 threadId: 8 done: 0th at 22.18859999999404 threadId: 9 done: 0th at 10.147300001233816 threadId: 10 done: 0th at 15.620099999010563 threadId: 1 done: 100th at 0.08020000159740448 threadId: 2 done: 100th at 0.10360000282526016 threadId: 5 done: 100th at 0.05690000206232071 threadId: 4 done: 100th at 0.05640000104904175 threadId: 6 done: 100th at 0.06940000131726265 threadId: 7 done: 100th at 0.10370000079274178 threadId: 8 done: 100th at 0.0575999990105629 threadId: 9 done: 100th at 0.056199997663497925 threadId: 10 done: 100th at 0.07080000266432762
|
预热后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| threadId: 1 done: 0th at 1.8744000010192394 threadId: 2 done: 0th at 2.410700000822544 threadId: 3 done: 0th at 2.3161999993026257 threadId: 4 done: 0th at 2.9968000017106533 threadId: 5 done: 0th at 2.564599998295307 threadId: 6 done: 0th at 3.0161999985575676 threadId: 7 done: 0th at 3.555900000035763 threadId: 8 done: 0th at 3.5732999965548515 threadId: 9 done: 0th at 3.471400000154972 threadId: 10 done: 0th at 3.1979999989271164 threadId: 3 done: 100th at 0.057099997997283936 threadId: 5 done: 100th at 0.05829999968409538 threadId: 6 done: 100th at 0.11400000005960464 threadId: 7 done: 100th at 0.05640000104904175 threadId: 8 done: 100th at 0.08650000020861626 threadId: 9 done: 100th at 0.06109999865293503 threadId: 10 done: 100th at 0.058400001376867294 threadId: 1 done: 100th at 0.06509999930858612 threadId: 2 done: 100th at 0.055799998342990875 threadId: 4 done: 100th at 0.06909999996423721
|