Как я могу улучшить скорость этого кода с помощью правильных async / await / promises - PullRequest
0 голосов
/ 22 февраля 2019

Используя Node.js, у меня есть задача улучшить код, который я создал.Этот код выполняет 60 HTTP-запросов и использует для этого библиотеки.

Для выполнения всех HTTP-запросов и сохранения каждого в файл требуется 30 секунд!

Говорят, что эти запросы можно выполнить за 3 секунды с помощью:

1.Правильное управление асинхронными обещаниями

2.Немного умнее кеширование

3.Не используется кластер

4.Добавляйте накладные расходы только один раз

Я боюсь, что я не уверен, с чего начать, чтобы понять, что я могу сделать точно.

Так что ниже код получает массив из 60 элементов, где каждыйэто один HTTP-запрос:

const exchanges = ccxt.exchanges

Они входят в функцию: worker = async и в конце кода: await Promise.all (работники) ждут их завершения.

Я не уверен, с чего начать, чтобы на самом деле можно было опускаться до 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 голосов
/ 22 февраля 2019

Я думаю, вы делаете вещи более сложными, чем они должны быть.Вы можете выполнить всю работу внутри обратного вызова 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`);
})();
0 голосов
/ 22 февраля 2019

Я пытаюсь понять, можно ли сделать это еще быстрее.Я пытаюсь кэшировать всю необходимую память. Прежде чем выполнить запрос .fetchTickers ().

Мне удалось снизить скорость до 15 секунд с 15 секунд, как казалось.Но приведенный ниже код является еще одним шагом вперед, но я получаю ошибки компиляции и не уверен, что делаю неправильно.

Ошибка:

ReferenceError: идентификатор не определен

Не передается ли id в объекте 'exchange', который помещается в '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`);
})();
...