javascript - 在工作线程之间共享负载的最佳方式
问题描述
在工作线程之间共享线性任务以提高性能的最佳方式是什么?
以下面的基本 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
}
工人.ts
self.onmessage = async (req) => {
//Peform some linear task on the request and make a response
};
分配任务的最佳方式会是这样吗?
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);
}
或者有没有更好的方法来做到这一点?例如,使用原子来确定哪些线程可以自由地接受另一个任务。
解决方案
当使用这样的 WorkerThread 代码时,我发现分配作业的最佳方法是让 WorkerThread 在 WorkerThread 知道它已完成之前的作业时向主线程请求作业。然后,主线程可以向它发送一个新作业以响应该消息。
在主线程中,我维护了一个作业队列和一个等待作业的 WorkerThreads 队列。如果作业队列为空,那么 WorkerThread 队列中可能会有一些 workerThreads 在等待作业。然后,每当一个作业被添加到作业队列中时,代码都会检查是否有 workerThread 正在等待,如果是,则将其从队列中移除并将其发送到下一个作业。
每当 workerThread 发送一条消息表明它已准备好进行下一个作业时,我们都会检查作业队列。如果那里有工作,则将其删除并发送给该工人。如果不是,则将工作线程添加到 WorkerThread 队列中。
这整个逻辑非常干净,不需要原子或共享内存(因为一切都通过主进程的事件循环进行门控)并且代码不多。
在尝试了其他几种方法后,我得出了这个机制,每种方法都有自己的问题。在一种情况下,我遇到了并发问题,在另一种情况下,我正在饿死事件循环,在另一种情况下,我没有对 WorkerThreads 进行适当的流控制,并且压倒了它们并且没有平均分配负载。
推荐阅读
- swift - eduroam 上的 URLSession GET 请求失败
- android - Android Studio 中的调试不再起作用
- memory - ROM硬件实现中的两个指针
- javascript - 动态表中的求和列
- discord.py - 将机器人分配给单通道 discord.py
- c++ - 需要加倍 sprintf 格式并返回太长的字符串
- php - Laravel 关系查询在哪里使用数组
- batch-file - 计算子目录中的子目录数
- javascript - ENABLE_NOTIFICATION_VALUE - 网络蓝牙 API
- c# - 用Sql中的表格填充网格视图中的下拉列表