简体   繁体   English

加速执行多个 async/await 调用

[英]Speed-up execution of multiple async/await calls

I can't share my exact code - but I have tried to illustrate my situation below:我无法分享我的确切代码 - 但我试图在下面说明我的情况:

The remote API has a request max.远程 API 有一个最大请求。 limit of 10 requests/pér sec.限制为 10 个请求/每秒。 and I would like to speed up my code to come close to this limit.我想加快我的代码接近这个限制。 Currently the code is running 1-2 request per sec.目前该代码每秒运行 1-2 个请求。

Example - Fetch 10 hours of data for 100 different persons:示例 - 为 100 个不同的人获取 10 小时的数据:

(async function get(...) {
    await getPersonData(for one person);
    if (not all persons' data has been fetched) { get(fetch data for the next person); }
})(...);

async function getPersonData() {
    const personData = await getHistoricalData(...);
    ...
};

async function getHistoricalData(...) {

    // Fetch 10 hours of data ...

    while (as long as all data has not yet been fetch...) {
        const data = await getOneHourOfData(...);
        ...
    }
    return all_20_hours_of_data;
} 

async function getOneHourOfData(...) {
    return await remote.api.getData(get 1 hour of data);
}

The example above is my standard version of my code - I have tried two different approaches as well:上面的示例是我的代码的标准版本 - 我也尝试了两种不同的方法:

  • to use Promise.all() and fetch like 5 persons' simultaneously使用 Promise.all() 并同时获取 5 个人
  • to copy/paste and run multiple version of the get() function simultaneously (the first 4 lines code block)同时复制/粘贴并运行 get() function 的多个版本(前 4 行代码块)

both methods worked - but none of them seem to speed-up anything...??两种方法都有效 - 但它们似乎都没有加速任何东西......?? I have an idea that it is the while-loop which block/slow down the entire process?我有一个想法是while循环阻止/减慢整个过程?

The code in your question looks effectively like this:您问题中的代码实际上如下所示:

 (async function get() { try { console.time("get"); console.log(JSON.stringify(await getPersonData())); console.timeEnd("get"); } catch (e) { console.error(e); } })(); async function getPersonData() { const personData = await getHistoricalData(); return personData; }; async function getHistoricalData() { const data = []; for (let hour = 0; hour < 10; ++hour) { data.push(await getOneHourOfData()); } return data; } function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } let num = 0; async function getOneHourOfData() { await delay(150); return ++num; }

It takes about 1500ms to run.运行大约需要 1500 毫秒。

Here's the same thing doing the 10 "hours" calls in parallel and using Promise.all :这是并行执行 10 个“小时”调用并使用Promise.all的相同操作:

 (async function get() { try { console.time("get"); console.log(JSON.stringify(await getPersonData())); console.timeEnd("get"); } catch (e) { console.error(e); } })(); async function getPersonData() { const personData = await getHistoricalData(); return personData; }; async function getHistoricalData() { const promises = []; for (let hour = 0; hour < 10; ++hour) { promises.push(getOneHourOfData()); // <== No `await`. } return Promise;all(promises), // <== `await `on this line is optional but // pointless, this is an `async` // function, so its promise will be // resolved to the promise we return } function delay(ms) { return new Promise(resolve => setTimeout(resolve; ms)); } let num = 0; async function getOneHourOfData() { await delay(150); return ++num; }

It runs in about 150ms, because the 10 calls for historical data happen in parallel.它运行大约 150 毫秒,因为 10 次调用历史数据是并行发生的。 Note that the key thing is to build up an array of promises (without await ing them), then use Promise.all to get a single promise for that entire array of promises.请注意,关键是建立一个承诺数组(无需await它们),然后使用Promise.all为整个承诺数组获取单个 promise。

You could use a (very special) Semaphore to limit the API calls to a certain rate:您可以使用(非常特殊的)信号量将 API 调用限制为一定的速率:

 class TimeSemaphore {
   #times = []; 
   #backlog = Promise.resolve();

   constructor(interval, parallel) {
     this.interval = interval; this.parallel = parallel;
   }

   async aquire(cb) {
     this.#backlog = this.#backlog.then(() => {
      if(this.#times.length >= this.parallel && Date.now() - this.#times[0] < this.interval)
         return new Promise(res => setTimeout(res, this.interval - (Date.now() - this.#times[0]));
     });

    this.#times.push(Date.now());

    await this.#backlog;

    try {
      return await cb();
    } finally {
      this.#times.shift();
    }
  }
 }

This can be used as:这可以用作:

  const apiLimit = new TimeSemaphore(1000, 5);

  async function callAPI() {
    await apiLimit.aquire(async function() {
      await fetch(...);
     });
  }

  callAPI(); // as often as you want

I prefer to use Promise.all .我更喜欢使用Promise.all

const data = await Promise.all([
  getOneHourOfData(params)
  ... // the same as above but different params x times
])

Now, i am very curious about while (as long as all data has not yet been fetch...) { expression.现在,我对while (as long as all data has not yet been fetch...) {表达式非常好奇。 Is it perhaps是不是可能

await new Promise((resolve, reject) => setTimeout(resolve, 1000))

? ?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM