我不确定这是猫鼬的错误还是我做错了。一旦我使用eachAsync
迭代光标时开始使用异步函数,我会遇到内存泄漏(快速上升到4gb然后崩溃)。在尝试了一些事情后,我注意到如果我不使用异步函数作为回调,就不会发生这种情况。
无内存泄漏:
const playerCursor: QueryCursor<IPlayerProfileModel> = PlayerProfile.find({}, projection).lean().cursor();
await playerCursor.eachAsync(
(profile: IPlayerProfileModel) => {
return;
},
{ parallel: 50 }
);
内存泄漏:
const playerCursor: QueryCursor<IPlayerProfileModel> = PlayerProfile.find({}, projection).lean().cursor();
await playerCursor.eachAsync(
async (profile: IPlayerProfileModel) => {
return;
},
{ parallel: 50 }
);
显然上面的代码没有任何意义,但我需要在函数内执行异步操作。
问题:
导致内存泄漏的原因/我该如何避免?
答案 0 :(得分:1)
它与async
functions的工作方式有关。
引用文档:
当异步函数返回一个值时,将解析Promise 返回值。
含义,async
函数返回的值将自动换行为Promise
。
在第一个代码示例中,代码返回undefined
,而在第二个代码示例中,代码返回Promise.resolve(undefined)
。
导致内存泄漏的原因是什么?
我没有查看mongoose
代码,只有the documentation个州:
如果fn返回一个promise,将在迭代到下一个之前等待promise的解析。
由于您的第一个示例没有返回Promise
,我认为您的回调是在每个结果上执行的,而不是按顺序执行。
我该如何避免呢?
我建议您在第二个代码示例中使用async/wait
。
在查看代码(自己寻找答案)之后,如果提供了一个不返回promise eachAsync
的回调,它将尽可能快地运行回调。
This line是执行回调的地方。下一行检查是否为Promise
,如果不是,则立即执行 callback
,这会在下一个结果上有效地调用eachAsync
回调。如果您的回调具有任何类型的异步操作但立即返回,那么您最终会同时运行成千上万的异步操作。
最重要的是,您将parallel
选项设置为100
,it executes eachAsync
callback one hundred times in parallel。
这不是mongoose
上的错误,因为有些情况需要此行为,并且它确实提供了使用Promise
的顺序处理。文档应该提到使用不返回Promise
的回调的警告。
再进一步,express
uses next
on middleware callbacks以便对它们进行排序。