如何通过适当的异步/等待/承诺来提高此代码的速度

时间:2019-02-21 21:42:09

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

使用Node.js,我有一个任务来改善自己创建的代码。此代码执行60个HTTP请求,并为此使用库。

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

据说可以在3秒内通过以下方式完成这些请求:

1。正确管理异步诺言

2。缓存更聪明

3。不使用群集

4。只需添加一次费用

恐怕我不确定从哪里开始了解我能做些什么。

因此下面的代码获得了一个包含60个项目的数组,其中每个项目都是一个HTTP请求:

const exchanges = ccxt.exchanges

这些代码进入:worker = async函数,并在代码末尾:等待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)

}) ()

2 个答案:

答案 0 :(得分:1)

我认为您正在使事情变得更加复杂。您可以在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`);
})();

答案 1 :(得分:0)

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

我设法从15秒降低到了9秒。但是下面的代码甚至更进一步,但是我确实收到编译错误,并且不确定我在做什么错。

错误是:

ReferenceError:未定义ID

不是将ID传递到被推送到“ exchangesArray”的“ exchange”对象中吗?

我一直在尝试将交换对象首先放入一个数组中,这需要花费所有时间:

class Challenge{

// your current code

   @Override
    public boolean equals(Object o) {

        if (o == this) return true;
        if (!(o instanceof Challenge)) {
            return false;
        }

        Challenge challenge = (Challenge) o;

        return challenge.name.equals(name) /*&& compare other values for equality*/;
        // also check for null name if it is necessary 
    }

    @Override
    public int hashCode() {
        int result = 17;
        result = 31 * result + name.hashCode();
        //result = 31 * result + age; // other property
        //result = 31 * result + passport.hashCode();// other property
        return result;
    }

}

然后使用此“ exchangesArray”,我尝试执行执行fetchTickers的功能:

var exchangesArray = [];