Javascript mongoDB中在同一API中并行查询同一文档
我有一个用typescript编写的API,我尝试使用promise.allSetted为同一文档运行并行查询,但是它的性能更差,我猜它们是按顺序运行的。是否有一种方法可以在mongoDB的同一连接中对同一文档执行并行查询。代码如下:Javascript mongoDB中在同一API中并行查询同一文档,javascript,mongodb,typescript,promise,parallel-processing,Javascript,Mongodb,Typescript,Promise,Parallel Processing,我有一个用typescript编写的API,我尝试使用promise.allSetted为同一文档运行并行查询,但是它的性能更差,我猜它们是按顺序运行的。是否有一种方法可以在mongoDB的同一连接中对同一文档执行并行查询。代码如下: console.time("normal"); let normal = await ContentRepo.geBySkillIdWithSourceFiltered( [chosenSkillsArr[0].sid!], r
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;
}
}
看起来您在并行版本中运行了更多的代码
//正常版本
let normal=wait ContentRepo.geBySkillIdWithSourceFiltered(
[chosenSkillsArr[0].sid!],
ReadContentID,
包括body.com在内,
是的,
真的
);
//并行版本中的代码:
chosenSkillsArr.map(异步(技能:isccilldocument)=>{
const result=wait ContentRepo.geBySkillIdWithSourceFiltered(
[skill.sid!],
ReadContentID,
包括body.com在内,
是的,
真的
);
})
对于并行版本,将函数调用(ContentRepo.geBySkillIdWithSourceFiltered
)放入循环中。这就是为什么它比较慢
关于并行运行承诺的问题:
像Promise.all
,Promise.allsolited
等待多个承诺。它不关心它们解析的顺序,也不关心计算是否并行运行。它们都不能保证并发性,也不能保证相反的情况。他们的任务只是确保传递给它的所有承诺都得到履行
因此,您无法手动保证承诺执行的并行性
下面是一个真正解释并行性和承诺的例子。所有的以及浏览器Nodejs API在并行性方面与计算机上安装的Nodejs API的区别
以下是文章结论的摘录:
JavaScript运行时是单线程的。我们无法访问JavaScript中的线程。即使您有多核CPU,也无法使用JavaScript并行运行任务。但是,browser/NodeJS使用C/C++(!)来访问线程。因此,它们可以实现并行性
旁注:
有一个细微的区别:
Promise.all:仅当传递给它的所有承诺都已解决时才解决,否则它将拒绝第一个已拒绝的承诺错误
Promise.allSettled:将始终使用包含有关已解决和已拒绝承诺的信息的数组进行解决
谢谢你的精彩解释。我试着答应,但没有使用地图,而是手工提出请求。但这并没有改变任何事情。我想这可能是与mongoDb有关的问题。您对在mongoDb中运行并行查询有何想法?我认为这不是mongoDb的问题,而是NodeJ的自治性及其单线程性。假设有10个人跑向柜台去买电影票。所有这些都是在完全相同的地点和时间开始的。有人会先到,柜台的职员会为最先到的人服务。考虑CPU和10个人的计数器是10个不同的承诺。无论是谁先开始,还是有人离柜台有多近,柜台一次只能为一个人服务。Nodejs就是这样。非常感谢您的帮助,那么我应该寻找其他方法来提高查询性能。很高兴我回答了您的问题。至少有一部分。请注意,尽可能避免将数据库调用放入循环中。
single-KS120B874P2P6BK1MQ0T: 1872.735ms
normal: 1873.934ms
single-KS120B874P2P6BK1MQ0T: 3369.925ms
single-KS440QS66YCBN23Y8K25: 3721.214ms
single-KS1226Y6DNDT05G7FJ4J: 3799.050ms
parallel: 3800.586ms
[chosenSkillsArr[0].sid!], vs chosenSkillsArr.map()