【问题标题】:Promise.map: Maximum call stack size exceededPromise.map:超出最大调用堆栈大小
【发布时间】:2019-05-29 05:19:31
【问题描述】:

我使用 bluebirds Promise.map() 方法运行 100,000 个 firebase 查询,如下所示,该函数运行大约需要 10 秒。如果我将并发设置为高于 1000,那么我会收到错误

超过最大调用堆栈大小

关于如何解决此问题以及如何加快此问题的任何想法。在我看来,也许 Promise.map() 可能不是正确使用的函数,或者我可能以某种方式对内存管理不善。任何想法谢谢。

exports.postMadeByFriend = functions.https.onCall(async (data, context) => {
            const mainUserID = "hJwyTHpoxuMmcJvyR6ULbiVkqzH3";
            const follwerID = "Rr3ePJc41CTytOB18puGl4LRN1R2"
            const otherUserID = "q2f7RFwZFoMRjsvxx8k5ryNY3Pk2"

            var refs = [];

            for (var x = 0; x < 100000; x += 1) {

                if (x === 999) {
                    const ref = admin.database().ref(`Followers`).child(mainUserID).child(follwerID)
                    refs.push(ref);
                    continue;
                }
                const ref = admin.database().ref(`Followers`).child(mainUserID).child(otherUserID);
                refs.push(ref);
            }

            await Promise.map(refs, (ref) => {
                return ref.once('value')
            }, {
                concurrency: 10000
            }).then((val) => {
                console.log("Something happened: " + JSON.stringify(val));
                return val;
            }).catch((error) => {
                console.log("an error occured: " + error);
                return error;
            })

编辑

const runtimeOpts = {
    timeoutSeconds: 300,
    memory: '2GB'
  }

exports.postMadeByFriend = functions.runWith(runtimeOpts).https.onCall(async (data, context) => {
            const mainUserID = "hJwyTHpoxuMmcJvyR6ULbiVkqzH3";
            const follwerID = "Rr3ePJc41CTytOB18puGl4LRN1R2"
            const otherUserID = "q2f7RFwZFoMRjsvxx8k5ryNY3Pk2"

            var refs = [];

            for (var x = 0; x < 100000; x += 1) {

                if (x === 999) {
                    const ref = admin.database().ref(`Followers`).child(mainUserID).child(follwerID)
                    refs.push(ref);
                    continue;
                }
                const ref = admin.database().ref(`Followers`).child(mainUserID).child(otherUserID);
                refs.push(ref);
            }

            await Promise.map(refs, (ref) => {
                return ref.once('value')
            }, {
                concurrency: 10000
            }).then((val) => {
                console.log("Something happened: " + JSON.stringify(val));
                return val;
            }).catch((error) => {
                console.log("an error occured: " + error);
                return error;
            })

【问题讨论】:

  • 你真的需要做这 100.000 次查询吗?您似乎希望向用户展示朋友发布的帖子。您也许可以使用无限滚动系统来加载 100 个帖子,然后当用户到达页面末尾时,它会自动加载下一个 100 个
  • 您正在检索 100.000 次相同的 mainUserID - follwerID 组合。这毫无意义..
  • 与例如 1000 相比,您是否获得了更好的性能? 500。更高的concurrency 并不意味着更好的性能,尤其是瓶颈肯定是网络连接(或一般的 API 连接)。
  • 回答:不要。您正在对第三方 API 进行并发调用,16-50 范围内的并发限制是绝对最大值。您只是要求限制速率。我会调查(a)您是否需要这些查询,(b)如果您需要它们,请在速度不那么重要的后台工作人员中进行。
  • @Weedoze 不幸的是,这是我基于此 asnwer stackoverflow.com/questions/53952903/… 能想出的唯一解决方案,本质上用户选择了一个标签,我想从一个标签中显示他们的关注者帖子高于另一个与标签有关的帖子。我能想到的最好方法是根据发布到特定标签的用户列表检查每个朋友

标签: javascript node.js promise es6-promise bluebird


【解决方案1】:

更新: 如果目标是让许多朋友发帖,那么更好的方法是拥有一个云功能,该功能会在每个保存到数据库的新帖子上增加一个计数器。这样你就可以得到帖子的数量而无需计算。

这是similar answercode sample with the like counter

原答案: 您可以尝试增加分配给 Cloud Funciton 的内存:

  1. 在 Google Cloud Platform Console 中,从左侧菜单中选择 Cloud Functions。
  2. 通过在函数列表中单击函数名称来选择函数。
  3. 点击顶部菜单中的编辑图标。
  4. 从标记为已分配内存的下拉菜单中选择内存分配。
  5. 点击保存更新函数。

Manage functions deployment 页面中所述

【讨论】:

  • 感谢您的回答,我尝试将分配的最大内存增加到 2GB,但仍然收到相同的错误。我在本地运行该功能我不确定这是否也会影响分配的最大数量。
  • 感谢您的更新,感谢您抽出宝贵时间帮助解决此问题。要实现一个计数器来记录一个朋友在标签上发表的帖子数量,需要的写入量与用户拥有的朋友数量成正比。每次用户发帖时,我都必须在其关注者的每个节点上增加计数器。
  • 没错。自然,该解决方案高度依赖于您的系统架构。但从总体上看:新帖数*用户好友数远低于浏览次数。基本上,您应该期望获得比新帖子更多的页面浏览量。通过将密集操作转移到写入时间,您可以为用户提供流畅的阅读体验。
猜你喜欢
  • 1970-01-01
  • 2015-10-24
  • 2015-12-29
  • 2017-12-27
  • 2020-12-06
  • 2018-02-06
  • 2020-06-28
  • 2016-02-28
  • 2019-05-21
相关资源
最近更新 更多