笑脸工
平行执行叉下繁重任务的模块,提供 Promise 基础接口、最低间接费用和捆绑工人.
该模块通过提供模块的绝对路径来工作,该模块将在所有前置过程中被加载. 所有方法都被暴露在母程序上,作为承诺,所以可以 await儿童(工人)方法可以是同步的,也可以是同步的.
该模块还为约束工人提供支持。 约束工人意味着,根据某些参数,同一工人将永远承担同样的任务。 捆绑工人的工作方式是使用返回的串 computeWorkerKey 方法。 如果在任务之前就使用过弦,则会将调用排到较早处理任务的相关工人;如果没有,则由第一个可用的工人执行,再被粘住到执行该任务的工人;所以下一次由同一个工人处理. 如果您对执行该任务的工人没有偏好,但您已经定义了 computeWorkerKey 方法,因为你想 有点 ,您可以返回 null 从它.
暴露方法清单可通过下列途径明确提供: exposedMethods 选项。 如果不提供,则需要将儿童单元纳入主要过程,并通过反思加以分析。 请检查archive-date=中的日期值 (帮助) "minmal example"一栏,为有效的一栏.
安装
yarn add jest-worker
示例
这个例子包括最低限度的使用:
文件 parent.js
import {Worker as JestWorker} from 'jest-worker';
async function main() {
const worker = new JestWorker(require.resolve('./worker'));
const result = await worker.hello('Alice'); // "Hello, Alice"
}
main();
文件 worker.js
export function hello(param) {
return `Hello, ${param}`;
}
实验工人
节点已运出 worker_threads,使用 SharedArrayBuffers 用于在主过程及其子线之间进行交流。 这一功能可大大地改善父母与子女在 jest-worker。 。 。 .
用于 worker_threads 而不是默认 child_process 你必须通过 enableWorkerThreads: true 当立即通知工人的时候.
API 密码
这个 Worker 导出是一个通过传递工人路径初始化的构造器,外加一个选项对象.
workerPath: string | URL (必须)
在孩子进程中要加载的文件的节点模块名称或绝对路径或文件URL. 你用得着 require.resolve 将相对路径转化为绝对路径.
options: Object (可选)
computeWorkerKey: (method: string, ...args: Array<unknown>) => string | null (可选)
每次通过API曝光的方法被调用, computeWorkerKey 也是为了把电话打给工人 这对于能够缓存结果或部分结果的工人是有用的. 你打给工人的电话 computeWorkerKey 返回所有不同呼叫的相同标识符。 如果你不想把电话绑在任何工人身上,请返回 null。 。 。 .
你提供的回调是用方法名调用,加上调用的所有其余参数. 因此,你完全可以决定 返回什么。 请检查access-date=中的日期值 (帮助) "约束工人用法"栏下关于约束工人的实践示例.
默认情况下,任何工人都不受程序约束.
enableWorkerThreads: boolean (可选)
默认, jest-worker 将使用 child_process 线程生成出新的节点.js进程. 如果你喜欢 worker_threads 相反,通过 enableWorkerThreads: true。 。 。 .
exposedMethods: ReadonlyArray<string> (可选)
从父进程可以调用到儿童进程的方法名称列表. 你不能暴露任何以公众身份命名的方法 Worker 方法,或从 _。如果使用自动发现方法,那么这些方法即使存在也不会被曝光.
forkOptions: ForkOptions (可选)
允许自定义所有转到的选项 child_process.fork。默认情况下,将设定一些值(cwd, (中文(简体) ), env, (中文(简体) ), execArgv 财务报告和审定财务报表 serialization),但你可以覆盖它们,并定制其余部分. 对于有效值列表,请检查 节点文档。 。 。 .
idleMemoryLimit: number (可选)
指定工人在被回收之前的内存限制,主要是为 这个问题· ;
工人执行任务后,将检查其内存使用情况。 如果超过指定的值,工人将被杀死并重新启动。 如果没有设定限制,则此过程不会发生. 限制可有两种方式:
<= 1- 假设值为系统内存的百分比。 0.5把工人的内存限制定为系统内存总量的一半\> 1- 假设是一个固定字节值。 因为之前的规则 如果你想要一个字节的值(我不知道为什么) 你可以使用1.1。 。 。 .
maxRetries: number (可选)
死亡孩子最多可以重生的次数,每个呼叫。 默认为 3,通过 Infinity 允许无休止的重复.
numWorkers: number (可选)
产卵工人数量。 默认为CPU数减 1.
resourceLimits: ResourceLimits (可选)
这个 resourceLimits 选项 worker_threads 工人们.
silent: Boolean (可选)
设置为虚假 stdout 财务报告和审定财务报表 stderr 要登录到控制台.
默认这是真的.
setupArgs: Array<unknown> (可选)
B. 将提交人权理事会的论据 setup 初始化时的方法.
taskQueue: TaskQueue (可选)
任务队列定义了由工人处理的顺序任务(方法调用). jest-worker 1. 具有下列特性的船舶: FifoQueue 财务报告和审定财务报表 PriorityQueue数字 :
FifoQueue(默认):处理调用命令中的方法调用(任务).PriorityQueue:按自然顺序中计算的优先次序处理方法调用(优先排序较低)。 具有相同优先权的任务按任何顺序处理(FIFO没有保证). 构造器接受一个单一的参数,这个函数被传递给所谓的函数的名称和参数,并返回优先级的数值:new require('jest-worker').PriorityQueue((method, filename) => filename.length)。 。 。 .
WorkerPool: new (workerPath: string, options?: WorkerPoolOptions) => WorkerPoolInterface (可选)
提供定制的工人Pool类,用于产卵过程.
workerSchedulingPolicy: 'round-robin' | 'in-order' (可选)
指定政策,如果有多个工人,如何为工人分配任务 闲置数字 :
round-robin(默认) : 这项工作将按顺序分配给工人。 第一项任务分配给工人1,第二项任务分配给工人2,以确保工作在工人之间分配.in-order:任务将分配给第一个从工人1开始的自由工人,只有在工人1忙碌的情况下才将工作分配给工人2.
一旦任务开始排队,任务总是分配给第一个免费工人. 调度政策没有定义总是先入先出的任务调度.
捷运工人
方法
回来的 JestWorker 与工人本身互动:
getStdout(): Readable
回返a ReadableStream 将所有工人的标准产出都管道化。 注意 silent 童工的选择必须确定为: true 让它发挥作用。 这是默认设置 jest-worker,但记住 当压倒性选项通过 forkOptions。 。 。 .
getStderr(): Readable
回返a ReadableStream 在那里,所有工人的标准差错都是空的。 注意 silent 童工的选择必须确定为: true 让它发挥作用。 这是默认设置 jest-worker,但记住 当压倒性选项通过 forkOptions。 。 。 .
start()
发动每一个工人 并打电话给他们的 setup 函数,如果存在。 回返a Promise 当所有工人在运行和完成他们的劳动时 setup。 。 。 .
如果您想在使用其他功能之前 热心地启动所有员工,这将会有所帮助.
end()
杀死所有工人完成工人。 不能再打进一步电话了 Worker 举个例子.
回返a Promise 解决与 { forceExited: boolean } 当所有工人都死了。 若为 forceExited 实值 true至少其中一名工人没有优雅地离开,这很可能是因为它执行了漏出的任务,留下了手柄。 应避免这种情况,强迫工人退出是防止造成许多孤儿的最后手段.
说明:
await旋转 end() 在工人不再需要之后立即承诺,然后在你的计划中做其他有用的事情,也许不是一个好主意。 如果工人必须被迫离开, jest-worker 可能经历多个强制退出阶段(如SIGTERM,后为SIGKILLL),并给全体工人大约1次单独退出的时间. 在此期间,你的计划将会等待,尽管可能不需要所有工人在继续被处决之前全部死亡.
考虑有意让这个承诺浮出水面(未处理的决议). 在您的程序完成剩下的工作并即将退出之后,节点进程将在所有的工人都死了之后等待承诺的解决,作为最后一个事件循环任务. 这样你就可以同时计算程序的时间和等待时间, 而且你没有不必要地拖延程序的产出.
工人身份证
每个工人都有一个独特的ID(指数从 '1'),作为工人内部的 process.env.JEST_WORKER_ID。 。 。 .
建立和摧毁儿童进程
儿童过程可以定义两种特殊方法(两种方法都可以同步):
setup():如果定义,则在孩子中任何方法的首次调用之前执行.teardown():如果定义,则由农场结束时执行.
更多实例
标准使用
这个例子涵盖了标准使用:
文件 parent.js
import {Worker as JestWorker} from 'jest-worker';
async function main() {
const myWorker = new JestWorker(require.resolve('./worker'), {
exposedMethods: ['foo', 'bar', 'getWorkerId'],
numWorkers: 4,
});
console.log(await myWorker.foo('Alice')); // "Hello from foo: Alice"
console.log(await myWorker.bar('Bob')); // "Hello from bar: Bob"
console.log(await myWorker.getWorkerId()); // "3" -> this message has sent from the 3rd worker
const {forceExited} = await myWorker.end();
if (forceExited) {
console.error('Workers failed to exit gracefully');
}
}
main();
文件 worker.js
export function foo(param) {
return `Hello from foo: ${param}`;
}
export function bar(param) {
return `Hello from bar: ${param}`;
}
export function getWorkerId() {
return process.env.JEST_WORKER_ID;
}
约束工人的使用:
这个例子包括: computeWorkerKey 方法 :
文件 parent.js
import {Worker as JestWorker} from 'jest-worker';
async function main() {
const myWorker = new JestWorker(require.resolve('./worker'), {
computeWorkerKey: (method, filename) => filename,
});
// Transform the given file, within the first available worker.
console.log(await myWorker.transform('/tmp/foo.js'));
// Wait a bit.
await sleep(10_000);
// Transform the same file again. Will immediately return because the
// transformed file is cached in the worker, and `computeWorkerKey` ensures
// the same worker that processed the file the first time will process it now.
console.log(await myWorker.transform('/tmp/foo.js'));
const {forceExited} = await myWorker.end();
if (forceExited) {
console.error('Workers failed to exit gracefully');
}
}
main();
文件 worker.js
import babel from '@babel/core';
const cache = Object.create(null);
export function transform(filename) {
if (cache[filename]) {
return cache[filename];
}
// jest-worker can handle both immediate results and thenables. If a
// thenable is returned, it will be await'ed until it resolves.
return babel.transformFileAsync(filename).then(result => {
cache[filename] = result;
return result;
});
}