【问题标题】:How can I improve the speed of this code with proper async/await/promises如何通过适当的 async/await/promises 提高此代码的速度
【发布时间】:2019-07-15 22:23:55
【问题描述】:

使用 Node.js,我的任务是改进我创建的代码。此代码执行 60 个 HTTP 请求并为此使用库。

处理所有 HTTP 请求并将每个请求保存到文件需要 30 秒!

据说可以在 3 秒内完成这些请求:

1.正确管理异步承诺

2。更智能的缓存

3.不使用集群

4.只添加一次开销

恐怕我不知道从哪里开始了解我到底能做什么。

所以下面的代码得到了一个包含 60 项的数组,其中每一项都是一个 HTTP 请求:

const exchanges = ccxt.exchanges

这些进入:worker = async 函数并在代码末尾:await Promise.all(workers) 等待它们完成。

我不知道从哪里开始才能真正降到 3 秒。怎样才能提高这段代码的速度?

'use strict';

const ccxt  = require ('ccxt')
    , log   = require ('ololog').noLocate // npm install ololog
    , fs    = require ('fs')

    // the numWorkers constant defines the number of concurrent workers
    // those aren't really threads in terms of the async environment
    // set this to the number of cores in your CPU * 2
    // or play with this number to find a setting that works best for you
    , numWorkers = 8

;(async () => {

    // make an array of all exchanges
    const exchanges = ccxt.exchanges

        .filter (id => ![ 'cap1', 'cap2' ].includes (id))

        // instantiate each exchange and save it to the exchanges list
        .map (id => new ccxt[id] ({
            'enableRateLimit': true,
        }))

    // the worker function for each "async thread"
    const worker = async function () {

        // while the array of all exchanges is not empty
        while (exchanges.length > 0) {

            // pop one exchange from the array
            const exchange = exchanges.pop()

            // check if it has the necessary method implemented
            if (exchange.has['fetchTickers']) {

                // try to do "the work" and handle errors if any
                try {

                    // fetch the response for all tickers from the exchange
                    const tickers = await exchange.fetchTickers()

                    // make a filename from exchange id
                    const filename = '/myproject/tickers/' + exchange.id + 'Tickers.json'

                    // save the response to a file
                    fs.writeFileSync(filename, JSON.stringify({ tickers }));

                } catch (e) { } //Error
            }
        }
    }

    // create numWorkers "threads" (they aren't really threads)
    const workers = [ ... Array (numWorkers) ].map (_ => worker ())

    // wait for all of them to execute or fail
    await Promise.all (workers)

}) ()

【问题讨论】:

  • 谁说有可能?我的意思是,如果您要以同步方式执行此操作,而不是在执行下一个呼叫之前等待每个呼叫完成。似乎您不想同步进​​行。
  • 减少您正在执行的请求数量。例如,找到一种方法将“exchanges”中的所有“fetchTickers”组合到一个请求中。
  • 顺便说一句,如果性能很重要,您为什么要使用writeFileSync?当同步操作运行时,节点事件循环被阻塞。
  • @James 我相信库中不可能将所有“fetchTickers”合并到一个请求中,因为它是完全不同的 URL
  • @Alberti Buonarroti 是的,这是我可以改进的一件事。我想知道是否有可能以某种比现在编码的更“并行”的方法运行这些请求?我得到的提示是以更明智的方式使用 async/await/promises。

标签: javascript node.js http promise async-await


【解决方案1】:

我尝试看看是否有可能做得更快。我尝试缓存所有可能需要的内存。在实际执行 .fetchTickers() 请求之前。

我设法从看起来的 15 秒缩短到了 9 秒。但是下面的代码更进一步,但我确实收到编译错误并且不确定我做错了什么。

错误是:

ReferenceError: id is not defined

id 不是在 .pushed 到 'exchangesArray' 的 'exchange' 对象中传递吗?

我正在尝试首先将交换对象放入一个数组中:

var exchangesArray = [];

然后有了这个“exchangesArray”,我尝试执行执行 fetchTickers 的函数:

'use strict';
const ccxt = require('ccxt');
const fs = require('fs');
const path = require('path');

//Cache some memories first
var exchangesArray = [];
(async () => {
  const allexchanges = ccxt.exchanges.filter((id) => !['coinmarketcap', 'theocean'].includes(id))
        .map(async (id) => {
            const Exchange = ccxt[id];
            const exchange = new Exchange({ enableRateLimit: true });
            if (exchange.has['fetchTickers']) {

                exchangesArray.push(exchange);
            }
        });

    await Promise.all(allexchanges);
})();

//Use cached memories to do the "fetchTickers()" as fast as possible
(async () => {
    const start = Date.now();

    const exchanges = exchangesArray;
    while (exchanges.length > 0) {

        // pop one exchange from the array
        const exchange = exchanges.pop()

        try {
            const tickers = await exchange.fetchTickers();
            const dumpFile = path.join(__dirname, 'exchanges', `${id}-Tickers.json`);
            await fs.promises.writeFile(dumpFile, JSON.stringify(tickers));
        } catch (e) {
            console.error(e);
        }

    }

    await Promise.all(exchanges);

    const end = Date.now();
    console.log(`Done in ${(end - start) / 1000} seconds`);
})();

【讨论】:

  • 我在纠结:exchangeArray.push(exchange);当 .pushed 到 'exchangesArray' 时,'exchange' 对象似乎没有所有信息?
【解决方案2】:

我认为你让事情变得比他们需要的更复杂。您可以在map 回调中完成所有工作,然后使用Promise.all(promises) 等待所有操作完成。此过程确实比预期的“3 秒”(在我的情况下为 15 秒)花费的时间更长,并且产生了很多错误(例如缺少 apiToken,或未实现 fetchTickers),但这可能是我的环境的问题(我'之前从未使用过ccxt,而且我没有任何apiTokens)。

这是我想出的实现,希望它可以帮助您满足您的需求:

const ccxt = require('ccxt');
const fs = require('fs');
const path = require('path');

(async () => {
    const start = Date.now();

    const dumps = ccxt.exchanges
        .filter((id) => !['coinmarketcap', 'theocean'].includes(id))
        .map(async (id) => {
            const Exchange = ccxt[id];
            const exchange = new Exchange({enableRateLimit: true});
            if (exchange.has['fetchTickers']) {
                try {
                    const tickers = await exchange.fetchTickers();
                    const dumpFile = path.join(__dirname, 'exchanges', `${id}-Tickers.json`);
                    await fs.promises.writeFile(dumpFile, JSON.stringify(tickers));
                } catch (e) {
                    console.error(e);
                }
            }
        });

    await Promise.all(dumps);

    const end = Date.now();
    console.log(`Done in ${(end - start) / 1000} seconds`);
})();

【讨论】:

  • 谢谢!代码很有趣,但是 .json 文件是空的吗?它们只包含这个字符串:“[object Object]”也许它很接近并且缺少一些我还没有弄清楚的东西?
  • 对,你需要先将对象转换为字符串,然后再写入文件。我对答案进行了编辑。
  • 是的,我也只是为了发布它。我也发现了 :) 谢谢你的代码。在这里下载也需要 15 秒,这是一个很大的改进。我会尝试看看是否可以将交换拆分为不同的转储/异步调用,以使它们以某种方式并行并使其更快:) 谢谢!
  • 请求和文件写入已经在并行运行,我不确定这可以进一步提高性能。
  • 是的,你是对的,我也不确定。不幸的是,图书馆的“大师”有一些方法可以在 3 秒内完成,但不会告诉我,而是让我试着找出来。
猜你喜欢
  • 2022-07-01
  • 1970-01-01
  • 2020-12-29
  • 1970-01-01
  • 1970-01-01
  • 2022-12-14
  • 2021-11-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多