在 mongoDB 中的同一 API 中并行查询同一文档

2024-04-12

我有一个用打字稿编写的 API,我尝试使用 Promise.allsettled 对同一文档运行并行查询,但它的性能更差,我猜它们是按顺序运行的。有没有办法在 mongoDB 的同一连接中对同一文档执行并行查询。这是代码:

console.time("normal");
let normal = await ContentRepo.geBySkillIdWithSourceFiltered(
    [chosenSkillsArr[0].sid!],
    readContentIds,
    body.isVideoIncluded,
    true,
    true
);
console.timeEnd("normal");

console.time("parallel");
const parallel = await Promise.allSettled(
    chosenSkillsArr.map(async (skill: IScrapeSkillDocument) => {
        const result = await ContentRepo.geBySkillIdWithSourceFiltered(
            [skill.sid!],
            readContentIds,
            body.isVideoIncluded,
            true,
            true
        );
    })
);
console.timeEnd("parallel");

我调用的函数在这里:

async geBySkillIdWithSourceFiltered(
    skillIds: string[],
    contentIds: string[],
    isVideoIncluded?: boolean,
    isCuratorIdFilter?: boolean,
    activeSourceFilter?: boolean
): Promise<IContentWithSource[]> {
    try {
        console.time(`single-${skillIds}`);
        var contents = await ContentM.find({
            $and: [
                { "skills.skillId": { $in: skillIds } },
                { recordStatus: true },
                isCuratorIdFilter ? { curatorId: 0 } : {},
                isVideoIncluded ? {} : { type: contentTypeNumber.read },
                { _id: { $nin: contentIds } },
            ],
        }).exec();
        var items: IContentWithSource[] = [];
        var sourceIds = new Set<string>();
        contents.forEach((content) => {
            if (!this.isEmpty(content.sourceId)) {
                sourceIds.add(content.sourceId!);
            }
        });
        var sources: any = {};
        var sourcesArr = await new SourceRepo().getByIds(
            Array.from(sourceIds)
        );
        sourcesArr.forEach((source) => {
            sources[source._id] = source;
        });

        if (activeSourceFilter) {
            contents
                .map((i) => i.toJSON() as IContentWithSource)
                .map((k) => {
                    if (sources[k.sourceId!].isActive) {
                        k.source = sources[k.sourceId!];
                        items.push(k);
                    }
                });
        } else {
            contents
                .map((i) => i.toJSON() as IContentWithSource)
                .map((k) => {
                    k.source = sources[k.sourceId!];
                    items.push(k);
                });
        }
        console.timeEnd(`single-${skillIds}`);

        return items;
    } catch (err) {
        throw err;
    }
}

结果是:

single-KS120B874P2P6BK1MQ0T: 1872.735ms
normal: 1873.934ms
single-KS120B874P2P6BK1MQ0T: 3369.925ms
single-KS440QS66YCBN23Y8K25: 3721.214ms
single-KS1226Y6DNDT05G7FJ4J: 3799.050ms
parallel: 3800.586ms

看来您在并行版本中运行了更多代码

// The normal version
let normal = await ContentRepo.geBySkillIdWithSourceFiltered(
    [chosenSkillsArr[0].sid!],
    readContentIds,
    body.isVideoIncluded,
    true,
    true
);


// The code inside the parallel version:
chosenSkillsArr.map(async (skill: IScrapeSkillDocument) => {
        const result = await ContentRepo.geBySkillIdWithSourceFiltered(
            [skill.sid!],
            readContentIds,
            body.isVideoIncluded,
            true,
            true
        );
    })
[chosenSkillsArr[0].sid!], vs  chosenSkillsArr.map()

对于并行版本,您将调用函数(ContentRepo.geBySkillIdWithSourceFiltered)在循环内。这就是为什么它比较慢。

对于并行运行 Promise 的问题:

Like Promise.all, Promise.allSettled等待多重承诺。它不关心它们解析的顺序,也不关心计算是否并行运行。它们都不保证并发,也不保证并发。他们的任务只是确保传递给它的所有承诺都得到处理。

所以你无法手动保证promise执行的并行性

这里有一个真正的有趣的文章 https://anotherdev.xyz/promise-all-runs-in-parallel/解释并行性和Promise.All以及浏览器 Nodejs API 与计算机上安装的 Nodejs API 在并行性方面有何不同。

以下是文章结论的摘录:

JavaScript 运行时是单线程的。我们无法在 JavaScript 中访问线程。即使您拥有多核 CPU,您仍然无法使用 JavaScript 并行运行任务。但是,浏览器/NodeJS 使用 C/C++(!),它们可以访问线程。因此,他们可以实现并行性。

边注:

有一个细微的差别:

  1. Promise.all:仅当传递给它的所有承诺都解决时才解决,否则它将拒绝第一个被拒绝的承诺错误。

  2. Promise.allSettled:始终会通过包含已解决和拒绝的 Promise 信息的数组来解决。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 mongoDB 中的同一 API 中并行查询同一文档 的相关文章

随机推荐