我不确定这是猫鼬的错误还是我做错了什么。一旦我在游标上迭代时开始使用异步函数,eachAsync我就会遇到内存泄漏(快速上升到 4GB 然后崩溃)。在尝试了一些事情之后,我注意到如果我不使用异步函数作为回调就不会发生这种情况。
无内存泄漏:
const playerCursor: QueryCursor<IPlayerProfileModel> = PlayerProfile.find({}, projection).lean().cursor();
await playerCursor.eachAsync(
(profile: IPlayerProfileModel) => {
return;
},
{ parallel: 50 }
);
Run Code Online (Sandbox Code Playgroud)
内存泄漏:
const playerCursor: QueryCursor<IPlayerProfileModel> = PlayerProfile.find({}, projection).lean().cursor();
await playerCursor.eachAsync(
async (profile: IPlayerProfileModel) => {
return;
},
{ parallel: 50 }
);
Run Code Online (Sandbox Code Playgroud)
显然上面的代码没有任何意义,但我需要在函数内执行异步操作。
题:
是什么导致内存泄漏/如何避免它?
它与async函数的工作方式有关。
引用文档:
当 async 函数返回一个值时,Promise 将使用返回值进行解析。
意思是,函数返回的async值将自动包装到Promise.
在您的第一个代码示例中,您的代码返回,undefined而在第二个代码示例中,您的代码返回Promise.resolve(undefined).
是什么导致内存泄漏?
我没有看mongoose代码,但文档指出:
如果 fn 返回一个承诺,将在迭代下一个承诺之前等待承诺解决。
由于您的第一个示例没有返回 a Promise,我认为您的回调是一次性对每个结果执行的,而不是按顺序执行的。
我怎样才能避免它?
我建议async/wait您在第二个代码示例中使用它。
查看代码后(自己寻找答案),如果提供了不返回承诺eachAsync的回调,则会尽可能快地运行回调。
这一行是执行回调的地方。下一行检查它是否是 a Promise,如果不是,则立即执行, callback这有效地eachAsync在下一个结果上调用您的回调。如果您的回调有任何类型的异步操作但立即返回,那么您最终会同时运行成千上万个异步操作。
最重要的是,你设置的选项parallel,以100使它执行eachAsync并行回调的一百倍。
这不是一个错误,mongoose因为在某些情况下需要这种行为并且它确实提供了使用Promise. 文档应该提到使用不返回Promise.
更进一步,express使用next中间件回调来对它们进行排序。
| 归档时间: |
|
| 查看次数: |
1367 次 |
| 最近记录: |