使用node.js并行操作数组元素?

3

I have a an array of json objects like this -

var resultsArr = [
{
    "upvotes": "45",
    "postID": "4555",
    "numberOfComments": "45",
    "shares":"22"
},
{
    "upvotes": "21",
    "postID": "4665",
    "numberOfComments": "20",
    "shares":"24"
},
{
    "upvotes": "4",
    "postID": "77366",
    "numberOfComments": "0",
    "shares":"4"
},
{
    "upvotes": "49",
    "postID": "6565",
    "numberOfComments": "22",
    "shares":"54",

}];

我需要根据upvotesnumberOfCommentsshares计算一个值score,然后将其推回JSON字典中,以便数组中的每个对象都是这样的 -

var resultsArr= [{
....
},
{
    "upvotes": "49",
    "postID": "6565",
    "numberOfComments": "22",
    "shares":"54",
    "score":"20"
}]

我可以使用for循环访问此数组中的json对象,但据我理解,它按顺序访问每个元素。
鉴于我将在数组中拥有大约100-200个项目,如何加速得分计算过程以并行访问每个元素,从而减少计算数组中每个元素的得分所需的时间?
附言:我正在编写此代码,并假设数组中的元素可能会增长到未来的300-400个元素。

300-400个元素对于任何语言来说都不是什么大问题。但是你对这些元素进行的处理可能会耗费时间。而且Node.js是单线程的。 - thefourtheye
3
不对。你有一个对象数组。JSON 是一种文本表示法。如果你在 JavaScript 代码中,并且不涉及字符串,那么你就不是在处理 JSON。将其推回 JSON 字典中的操作称为对象操作。 - T.J. Crowder
提醒一下,自您最初发布此问题以来情况已经发生了变化,我已经更新了我的答案。 - T.J. Crowder
2个回答

1
在下方的----下面,原始答案是在2015年编写的,并且当时是正确的。从那时起,Node.js获得了 worker threads。但是它们只能与SharedArrayBuffer共享内存,并且您无法在SharedArrayBuffer中存储对象(除非以某种序列化形式),SharedArrayBuffer只能与使用数字元素的typed arrays一起使用。
您可以将数组从一个线程转移到另一个线程(发送线程失去对其的访问权,接收线程获得访问权),因此您可以启动N个线程并将数组的一部分传输到每个线程中。他们将并行处理它并将结果发布回主线程。
只是一个简单的草图:
const { Worker } = require("worker_threads"); // If still using Node.js's CJS modules

function processChunkInWorker(script, chunk) {
    return new Promise((resolve, reject) => {
        const w = new Worker(script, {
            workerData: chunk
        });
        w.on("message", result => {
           resolve(result);
        });
    });
}
async function setScores(data, workerCount = 4) {
    const chunkSize = Math.round(data.length / workerCount);
    await Promise.all(
        Array.from({length: workerCount}, async (_, index) => {
            let chunkStart = index * chunkSize;
            const chunkEnd = index < workerCount - 1 ? (chunkStart + chunkSize) : data.length;
            const scores = await processChunkInWorker("./calcscore.js", data.slice(chunkStart, chunkEnd));
            for (const score of scores) {
                data[chunkStart++].score = score;
            }
        })
    );
}

(async () => {
    try {
        const data = /*...load the data...*/;
        await setScores(data);
        console.log(data);
    } catch (e) {
        console.error(e.message, e.stack);
    }
})();

其中calcscore.js类似于:

const { Worker, isMainThread, parentPort, workerData } = require("worker_threads"); // If still using Node.js's CJS modules
if (!isMainThread) {
    const scores = new Float64Array(workerData.map(({upvotes, numberOfComments, shares}) => +upvotes + +numberOfComments + +shares));
    parentPort.postMessage(scores, scores.buffer);
}

原始答案:

如何加速得分计算过程以并行访问每个元素,从而减少计算数组中每个元素的得分所需的时间?

你不能(合理地)这样做。NodeJS只运行单个线程。要获得多个执行线程,您必须生成一个子进程,这将比仅在一个线程上执行要慢得多。

300-400个元素不算什么(即使是3-4百万个元素也不算什么; 3M在我的机器上花费了约289ms,4M花费了384ms)。没有必要把事情弄复杂。只需:

resultsArr.forEach(function(entry) {
    // update `entry` here
});

0

我通常使用这段小代码

    loopWithPromises = async (array, callback) => Promise.all(array.map(callback))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接