NodeJS, обещания и производительность
Мой вопрос касается производительности в моем приложении NodeJS...
Если моя программа запускает 12 итераций по 1.250.000 каждая = 15.000.000 итераций вместе - для обработки потребуется выделенный сервер в Amazon:
r3.large: 2 vCPU, 6,5 ECU, 15 ГБ памяти -> 123 минуты
4.8xlarge: 36 vCPU, 132 ECU, 60 ГБ памяти -> 102 минуты
У меня есть код, похожий на код ниже...
start(); start(){ for(var i=0; i<12; i++){ function2(); // Iterates over a collection - which contains data split up in intervals - by date intervals. This function is actually also recursive - due to the fact - that is run through the data many time (MAX 50-100 times) - due to different intervals sizes... } } function2(){ return new Promise{ for(var i=0; i<1.250.000; i++){ return new Promise{ function3(); // This function simple iterate through all possible combinations - and call function3 - with all given values/combinations } } } } function3(){ return new Promise{ // This function simple make some calculations based on the given values/combination - and then return the result to function2 - which in the end - decides which result/combination was the best... }}
Это равно 0,411 миллисекунды / 441 микросекунды за итерацию!
Когда я смотрю на производительность и использование памяти на панели задач... ЦП не работает на 100% - но больше похоже на 50%... все время? Использование памяти начинается очень низко - но KEEPS растет в ГБ - каждую минуту, пока процесс не будет завершен - НО (выделенная) память сначала освобождается, когда я нажимаю CTRL+C в Windows CMD... так что это похоже на сборку мусора NodeJS не работает оптимально - или может быть просто дизайн кода снова...
Когда я запускаю приложение, я использую память как:
узел --max-old-space-size="50000" server.js
ПОЖАЛУЙСТА, расскажи мне все, что ты можешь сделать, чтобы сделать мою программу БЫСТРЕЕ!
Большое спасибо всем вам!
1 ответ
Дело не в том, что сборщик мусора не работает оптимально, а в том, что он вообще не работает - вы не даете ему никакого шанса.
При разработке модуля tco, который выполняет оптимизацию вызовов в Node, я заметил странную вещь. Казалось, утечка памяти, и я не знал, почему. Оказалось, что это из-за console.log()
вызовы в разных местах, которые я использовал для тестирования, чтобы увидеть, что происходит, потому что просмотр результата рекурсивного вызова глубиной в миллионы уровней занял некоторое время, поэтому я хотел что-то увидеть, пока он это делал.
Ваш пример очень похож на это.
Помните, что Node является однопоточным. Когда ваши вычисления выполняются, больше ничего не может - включая GC. Ваш код является полностью синхронным и блокирующим, даже если он генерирует миллионы обещаний блокирующим образом. Он блокируется, потому что никогда не достигает цикла обработки событий.
Рассмотрим этот пример:
var a = 0, b = 10000000;
function numbers() {
while (a < b) {
console.log("Number " + a++);
}
}
numbers();
Это довольно просто - вы хотите напечатать 10 миллионов номеров. Но когда вы запускаете его, он ведет себя очень странно - например, он печатает числа до некоторой точки, а затем останавливается на несколько секунд, затем продолжает работать или, возможно, начинает сбрасывать, если вы используете swap, или, возможно, выдает эту ошибку, которая Я только что понял, увидев номер 8486:
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
Aborted
Здесь происходит то, что основной поток блокируется в синхронном цикле, где он продолжает создавать объекты, но GC не имеет возможности их освободить.
Для таких длительных задач вам нужно разделить свою работу и время от времени попадать в цикл обработки событий.
Вот как вы можете решить эту проблему:
var a = 0, b = 10000000;
function numbers() {
var i = 0;
while (a < b && i++ < 100) {
console.log("Number " + a++);
}
if (a < b) setImmediate(numbers);
}
numbers();
Он делает то же самое - печатает номера изa
вb
но в пакетах по 100, а затем он планирует себя продолжить в конце цикла событий.
Выход из$(which time) -v node numbers1.js 2>&1 | egrep 'Maximum resident|FATAL'
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory
Maximum resident set size (kbytes): 1495968
Он использовал 1,5 ГБ памяти и упал.
Выход из$(which time) -v node numbers2.js 2>&1 | egrep 'Maximum resident|FATAL'
Maximum resident set size (kbytes): 56404
Он использовал 56 МБ памяти и закончил.
Смотрите также эти ответы: