Javascript 在工作线程之间共享负载的最佳方式

Javascript 在工作线程之间共享负载的最佳方式,javascript,node.js,typescript,multithreading,deno,Javascript,Node.js,Typescript,Multithreading,Deno,在工作线程之间共享线性任务以提高性能的最佳方式是什么 以下面的基本Deno web服务器为例: 主线程 // Create an array of four worker threads const workers = new Array<Worker>(4).fill( new Worker(new URL("./worker.ts", import.meta.url).href, { type: "module",

在工作线程之间共享线性任务以提高性能的最佳方式是什么

以下面的基本Deno web服务器为例:

主线程

// Create an array of four worker threads
const workers = new Array<Worker>(4).fill(
    new Worker(new URL("./worker.ts", import.meta.url).href, {
        type: "module",
    })
);

for await (const req of server) {
    // Pass this request to worker a worker thread
}


分配任务的最佳方式会是这样的吗

function* generator(): Generator<number> {
    let i = 0;
    while (true) {
        i == 3 ? (i = 0) : i++;
        yield i;
    }
}

const gen = generator();

const workers = new Array<Worker>(4).fill(
    new Worker(new URL("./worker.ts", import.meta.url).href, {
        type: "module",
    })
);

for await (const req of server) {
    // Pass this request to a worker thread
    workers[gen.next().value].postMessage(req);
}
函数*生成器():生成器{
设i=0;
while(true){
i==3?(i=0):i++;
产量一;
}
}
const gen=生成器();
常量工作者=新数组(4)。填充(
新工作者(新URL(“./Worker.ts”,import.meta.URL).href{
类型:“模块”,
})
);
用于等待(服务器的常量请求){
//将此请求传递给工作线程
workers[gen.next().value].postMessage(请求);
}


还是有更好的方法?比如说,使用Attomics来确定哪些线程可以自由接受另一个任务。当使用这样的WorkerThread代码时,我发现分发作业的最佳方法是让WorkerThread在WorkerThread知道它是使用前一个作业完成的情况下向主线程请求一个作业。然后,主线程可以向其发送一个新作业来响应该消息

在主线程中,我维护了一个作业队列和一个等待作业的WorkerThreads队列。如果作业队列为空,则WorkerThread队列中可能有一些WorkerThread在等待作业。然后,每当将作业添加到作业队列时,代码都会检查是否有workerThread在等待,如果有,则将其从队列中移除并发送给下一个作业

每当workerThread发送一条消息指示它已准备好进行下一个作业时,我们都会检查作业队列。如果那里有作业,它将被删除并发送给该工人。如果不是,则将工作线程添加到WorkerThread队列

整个逻辑非常干净,不需要原子或共享内存(因为所有内容都是通过主进程的事件循环进行选通的),也不需要太多代码


我是在尝试了其他几种各自有问题的方法后得出这个机制的。在一个案例中,我遇到了并发问题,在另一个案例中,我饥饿事件循环,在另一个案例中,我没有对WorkerThreads进行适当的流控制,使它们无法承受,并且没有平均分配负载。

这是一个非常好的答案!您是否可以使用该示例的修改版本对其进行更新,以向未来的查看者演示您的解决方案?此外,在工作线程之间传递大量消息是否会产生开销成本?在一次收到多个请求的情况下,Atomics不是更快吗?@Eidolon-只需向工作线程发送消息或从工作线程发送消息就可以了。但是,如果要随这些消息发送大量数据,则(默认情况下)必须复制这些数据,并且使用一些共享内存可能会提高性能。这真的取决于你在做什么。@Eidolon-我个人觉得通过事件队列而不是使用原子来协调Javascript中的线程更容易(我发现设计无bug代码更简单、更简单)。如果多个线程希望访问相同的数据(在共享内存中),则需要原子,但如果您将数据交给一个线程,并且只有一个线程处理给定的数据段,则不需要原子。@Eidolon-FYI包含一个
WorkerList
类,该类使用承诺而不是作业队列。有作业要做的代码doesconst worker=await workerList.get()解决此问题后,它可以向其发送作业。当工人发出完成工作或首次创建工作的信号时,他们会被放入工人列表。
function* generator(): Generator<number> {
    let i = 0;
    while (true) {
        i == 3 ? (i = 0) : i++;
        yield i;
    }
}

const gen = generator();

const workers = new Array<Worker>(4).fill(
    new Worker(new URL("./worker.ts", import.meta.url).href, {
        type: "module",
    })
);

for await (const req of server) {
    // Pass this request to a worker thread
    workers[gen.next().value].postMessage(req);
}