import { expose, transfer, wrap } from 'comlink'; import { box, spawn } from './core.js'; /** ## `Threads` : Worker线程管理 + 如果任务在执行过程中,CPU 使用率持续在`100%`,那么这个任务就是 CPU 密集型任务,适合使用多线程来提高性能。 + 线程`创建时`**最费时**,大概需要`>10ms`(取决于代码量),如果是临时创建并销毁的线程,那么要考虑 `代码执行时间` >> `线程创建时间` ?。 + 对于大多数 CPU 密集型任务,通常执行` 2-8 `个线程就能看到很好的效果,创建过多的线程可能会导致性能下降。可以使用{@linkcode Task}来控制执行线程数量 @example 密集型计算Bench ```ts // 使用斐波那契数列表示密集型计算 function fbnq(n: number): number { if (n <= 1) return n return fbnq(n - 1) + fbnq(n - 2) } const BENCH = 38 Deno.bench('main-threads', () => { Array.from({ length: 8 }, (_, i) => fbnq(BENCH)) }) // 2.9 s(time/iter) Deno.bench('worker-threads', async () => { await Promise.all(Array.from({ length: 8 }, (_, i) => Threads.spawn(fbnq)).map((worker) => worker.join(BENCH))) }) // 585.1 ms(time/iter) ``` */ export declare const Threads: { /** ### `box` : 数据代理包装 + 将任何可以在 `JavaScript` 运行时中作为`引用传递`的`对象`和`函数`进行代理包装,使得在`Worker`环境中能远程调用这些对象的方法或执行这些函数 + 用于包装的`函数` (不可结构化数据) 或`对象` (结构化太费时数据) ,其运行环境都是在`主线程`中运行 @example 包装函数 ```ts // Worker Thread async function callback_fn(cb_fbnq: (n: number) => Promise): Promise { return await cb_fbnq(10) } Threads.expose({ fbnq, callback_fn }) // Main Thread function fbnq(n: number): number { return n <= 1 ? n : fbnq(n - 1) + fbnq(n - 2) } const worker = new Worker(new URL('./work.ts', import.meta.url), { type: 'module' }) const thread = Threads.use(worker) // 要传入fn到子线程,由于函数带有主线程的运行上下文,所以需要使用box将函数进行包装 // 让函数在主线程执行完毕后将加过传给子线程 const func = Threads.box(fbnq) const res = await thread.callback_fn(func) worker.terminate() assert.equal(res, 55) ``` */ readonly box: typeof box; /** ### `move` : 显式指定可转移对象,将数据所有权从主线程传输到Worker线程 + 一般情况下,线程传输数据都是通过[结构化克隆算法](https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Structured_clone_algorithm)将数据克隆到Worker线程中。但是如果涉及到大数据传输(譬如ArrayBuffer)时,结构化克隆算法会非常耗时。因此需要显式指定可转移对象,将数据所有权从主线程传输到Worker线程 + 数据从主线程传输到Worker线程后,主线程将无法再访问这些数据,因为它们已经被转移了所有权。而Worker线程则可以访问这些数据,并且可以在Worker线程中修改这些数据。 @example ```ts // 创建一个包含 buffer 的对象 const dataToSend = { id: 1, name: 'large_payload', buffer: buffer // 注意这里是原始的 buffer }; const fc = Threads.use(new Worker('xxx.tx')) // 1.转移数据 - dataToSend | 2.显式指定可转移对象 - dataToSend.buffer fc.run(Threads.move(dataToSend,[dataToSend.buffer])) ``` */ readonly move: typeof transfer; /** * ### `use` : 调起`Worker`线程 * @example ```ts // Worker Thread import { Threads } from '@chzky/core' function fbnq(n: number): number { if (n <= 1) return n return fbnq(n - 1) + fbnq(n - 2) } Threads.expose({ fbnq }) // Main Thread type WorkerExport = { fbnq: (a: number) => number } const worker_uri = new URL('./work.ts', import.meta.url) const tcall = Threads.use(new Worker(worker_uri, { type: 'module' })) const res = await tcall.fbnq(10) assert.equal(res, 55) ``` */ readonly use: typeof wrap; /** * ### `expose` : 将数据暴露给主线程 * @example ```ts // Worker function foo(str) { return str + ' world' } Threads.expose({ foo }) // Main const fc = Threads.use(new Worker('worker.ts')) const words = await fc.foo('Hellow') assert(words === 'Hellow world') ``` */ readonly expose: typeof expose; /** ### `spawn` : 创建一个Worker线程,并执行函数 + 函数必须是`纯函数` , 所有的外部数据都应该由参数传入 * @example ```ts // 使用斐波那契数列表示密集型计算 function fbnq(n: number): number { if (n <= 1) return n return fbnq(n - 1) + fbnq(n - 2) } const BENCH = 38 const max_threads = cpus().length Deno.bench('main-threads', () => { Array.from({ length: max_threads }, (_, _i) => fbnq(BENCH)) }) // 2.9 s(time/iter) Deno.bench('worker-threads', async () => { await Promise.all( Array.from({ length: max_threads }, (_, _i) => Threads.spawn(fbnq)).map(worker => worker.join(BENCH) ) ) }) // 585.1 ms(time/iter) ``` */ readonly spawn: typeof spawn; }; //# sourceMappingURL=class.d.ts.map