setInterval,代码在这里,但因为它对线程什么都没做(我们重用
setTimeout的代码),所以我决定不在这里进行解释。我已经创建了一个短小的测试代码,目的是检查这种方法与原生方法的不同之处。你可以在这里找到代码。这些是结果:
native setTimeout { ms: 7004, averageCPUCost: 0.1416 }
worker setTimeout { ms: 7046, averageCPUCost: 0.308 }我们可以看到
setTimeout 有一点延迟 – 大约40ms – 这时 worker 被创建时的消耗。平均 CPU 成本也略高,但没什么难以忍受的(CPU 成本是整个过程持续时间内 CPU 使用率的平均值)。如果我们可以重用 worker,就能够降低延迟和 CPU 使用率,这就是要实现工作池的原因。
实现工作池
如上所述,工作池是给定数量的被事先创建的 worker,他们保持空闲并监听
message 事件。一旦
message 事件被触发,他们就会开始工作并发回结果。为了更好地描述我们将要做的事情,下面我们来创建一个由八个 thread worker 组成的工作池:
const pool = new WorkerPool(path.join(__dirname, './test-worker.js'), 8);如果你熟悉限制并发操作,那么你在这里看到的逻辑几乎相同,只是一个不同的用例。
如上面的代码片段所示,我们把指向 worker 的路径和要生成的 worker 数量传给了
WorkerPool 的构造函数。
export class WorkerPool<T, N> {
private queue: QueueItem<T, N>[] = [];
private workersById: { [key: number]: Worker } = {};
private activeWorkersById: { [key: number]: boolean } = {}; public constructor(public workerPath: string, public numberOfThreads: number) {
this.init();
}
}
这里还有其他一些属性,如
workersById 和
activeWorkersById,我们可以分别保存现有的 worker 和当前正在运行的 worker 的 ID。还有
queue,我们可以使用以下结构来保存对象:
type QueueCallback<N> = (err: any, result?: N) => void;interface QueueItem<T, N> {
callback: QueueCallback<N>;
getData: () => T;
}
callback 只是默认的节点回调,第一个参数是错误,第二个参数是可能的结果。
getData









