Не в состоянии выполнить обещания из-за нехватки памяти
У меня есть скрипт, чтобы очистить ~1000 веб-страниц. Я использую Promise.all, чтобы запустить их вместе, и он возвращается, когда все страницы сделаны:
Promise.all(urls.map(url => scrap(url)))
.then(results => console.log('all done!', results));
Это мило и правильно, за исключением одного - машина выходит из памяти из-за одновременных запросов. Я использую jsdom
для утилизации, это быстро занимает несколько ГБ памяти, что понятно, учитывая, что он создает сотни window
,
У меня есть идея исправить, но мне это не нравится. То есть, измените поток управления, чтобы не использовать Promise.all, но цепочка моих обещаний:
let results = {};
urls.reduce((prev, cur) =>
prev
.then(() => scrap(cur))
.then(result => results[cur] = result)
// ^ not so nice.
, Promise.resolve())
.then(() => console.log('all done!', results));
Это не так хорошо, как Promise.all... Не является производительным, поскольку он связан, и возвращаемые значения должны быть сохранены для последующей обработки.
Какие-либо предложения? Должен ли я улучшить поток управления, или я должен улучшить использование mem в scrap(), или есть ли способ позволить узлу регулировать распределение памяти?
1 ответ
Вы пытаетесь запустить 1000 веб-срезов параллельно. Вам нужно будет выбрать какое-то число, значительно меньшее 1000, и одновременно запускать только N, чтобы при этом вы потребляли меньше памяти. Вы все еще можете использовать обещание, чтобы отслеживать, когда они все будут выполнены.
Bluebird - х Promise.map()
может сделать это для вас, просто передав значение параллелизма в качестве опции. Или вы можете написать это сами.
У меня есть идея исправить, но мне это не нравится. То есть, измените поток управления, чтобы не использовать Promise.all, но цепочка моих обещаний:
То, что вы хотите, это N операций в полете одновременно. Секвенирование - это особый случай, когда N = 1
что часто будет намного медленнее, чем делать некоторые из них параллельно (возможно, с N = 10
).
Это не так хорошо, как Promise.all... Не является производительным, поскольку он связан, и возвращаемые значения должны быть сохранены для последующей обработки.
Если сохраненные значения являются частью вашей проблемы с памятью, вам, возможно, придется хранить их в памяти где-нибудь. Вам придется проанализировать, сколько памяти используют сохраненные результаты.
Какие-либо предложения? Должен ли я улучшить поток управления, или я должен улучшить использование mem в scrap(), или есть ли способ позволить узлу регулировать распределение памяти?
Используйте Bluebird's Promise.map()
или напишите что-нибудь подобное самостоятельно. Написание чего-либо, выполняющего до N операций параллельно и сохраняющего все результаты в порядке, не является ракетостроением, но это немного трудоемко, чтобы сделать это правильно. Я представил это раньше в другом ответе, но сейчас не могу найти его. Я буду продолжать искать.
Нашел мой предыдущий связанный ответ здесь: сделайте несколько запросов к API, который может обрабатывать только 20 запросов в минуту