Promise.all消耗我所有的RAM

时间:2017-10-09 20:12:08

标签: javascript node.js bluebird

我有一个我正在使用的API的速率限制器,它允许每秒20个请求。所有请求都是基于承诺的,一旦有响应,承诺将通过API数据解决。

问题:

我设置了一个promiseArray,它包含所有等待响应的58k promises。所以内存越来越慢,直到我内存不足为止。在我的具体情况下,我不需要将已解析的数据传递给我的then(),数据占用了我的所有内存。

代码:

  }).then(() => {
    // 2. Crawl for all clanprofiles from these leaderboards
    const promiseArray = []
    for (let i = 0; i < clanTags.length; i++) {
      // Resolved data from getClanProfile() is eating up all my RAM
      const p = backgroundScheduler.getClanProfile(clanTags[i], true)
      promiseArray.push(p)
    }
    return Promise.all(promiseArray)
  }).then(() => {

那么有没有办法等待promiseArray被解析而不需要解析数据?

1 个答案:

答案 0 :(得分:4)

如果您没有58k承诺,它们关联的异步操作及其结果数据一次处于活动状态,您将使用较少的内存。

相反,你想要立即运行X操作,然后当一个完成时,你开始下一个同时飞行中的X不超过X,并且一次使用X承诺。

您可以尝试使用适当的X值。值为1是顺序操作,但您通常可以通过使用更高的X值来改善整体端到端操作时间。如果所有请求都在同一主机上,然后X可能不超过5-10(因为一个给定的主机不能真正做到很多事情,并要求它做的比它能做的更多,而不是一次只能减慢速度)。

如果每个请求都是针对不同的主机,那么您可以使X更高。实验将为您提供峰值内存使用率和总吞吐量的最佳值,并且在某种程度上取决于您的具体情况。

Bluebird的Promise.map()有一个并发选项,可以为你做这个,但是也有很多方法可以同时为飞行中的X编码。

以下是一些其他编码示例,用于管理一次飞行中的数量:

Make several requests to an API that can only handle 20 request a minute

How to execute promises in series?

unable to complete promises due to out of memory

Fire off 1,000,000 requests 100 at a time

How to make it so that I can execute say 10 promises at a time in javascript to prevent rate limits on api calls?

如果您不需要已解析的数据,可以通过更换它来更快地进行GC:

  const p = backgroundScheduler.getClanProfile(clanTags[i], true).then(data => {
      return 0;     // make resolved value just be a simple number
                    // so other data is now eligible for GC
  });
  promiseArray.push(p)    

而且,这是一个简单的实现,可以同时迭代一个不超过X个请求的数组:

// takes an array of items and a function that returns a promise
// runs no more than maxConcurrent requests at once
function mapConcurrent(items, maxConcurrent, fn) {
    let index = 0;
    let inFlightCntr = 0;
    let doneCntr = 0;
    let results = new Array(items.length);
    let stop = false;

    return new Promise(function(resolve, reject) {

        function runNext() {
            let i = index;
            ++inFlightCntr;
            fn(items[index], index++).then(function(val) {
                ++doneCntr;
                --inFlightCntr;
                results[i] = val;
                run();
            }, function(err) {
                // set flag so we don't launch any more requests
                stop = true;
                reject(err);
            });
        }

        function run() {
            // launch as many as we're allowed to
            while (!stop && inflightCntr < maxConcurrent && index < items.length) {
                runNext();
            }
            // if all are done, then resolve parent promise with results
            if (doneCntr === items.length) {
                resolve(results);
            }
        }

        run();
    });
}
相关问题