И конечно же в случае кластера вы не ставили nginx перед node…
Чтобы упростить задачу, у php-fpm снизьте до 1 server-start (и 0 чилдов), потому что у вас в 5 раз больше php обработчиков (которые работают как треды, а не как воркеры), а результат всего на 23% лучше, что говорит не в пользу php
Нет, промисы дешево стоят, не сильно дороже callback (особенно если использовать bluebird)
Вы закрыли соединение до того, как промисы успели обратиться к базе. Поэтому они выкидывают сообщения об ошибках, а не тестируют соединение. А вот выкидывать сообщения об ошибках уже более дорогая операция, чем соединение
Тесты в цикле нельзя просто прогнать, нужно еще результат запомнить и прочитать его после цикла, иначе оптимизатор просто выкинет половину из цикла, или вовсе схлопнет цикл
Из статьи видим, что php это делает более агрессивно чем js, достаточно добавить немного «логики» в вычисления и php уже отстаёт
Хоть wrk, хоть ab (которые действительно надо запускать не на тестируемой машине, а на удаленной)
Автор всё равно сравнивает 5 тредов php-fpm против 1-го в ноде
Нужно либо ноду в кластере запускать, либо у php-fpm дефолтные настройки снизить
Если добавить немного «логики» в вычисления, и запоминать результат вычислений, то разница уже не в пользу php (кроме ассоциативного массива, с которым в js всегда было не очень хорошо, и на замену сейчас рекомендуется использовать Map там где критична скорость)
node 7.3.0
test1 (str): 67.853ms
str len: 1000000 sb
test2 (sum): 8.685ms
sum: 2500000
test3 (array): 53.455ms
array len: 1000000 z
test4 (obj): 1036.474ms
obj1: b
obj2: a
test Map: 575.344ms
obj1: b
obj2: a
php 7.1.1
test1 (str): 83.961ms
str len: 1000000 sb
test2 (sum): 69.857ms
sum: 2500000
test3 (array): 63.453ms
array len: 1000000 z
test4 (obj): 206.375ms
obj1: b
obj2: a
для js например
let intns = 1000000
console.log(`\n`)
console.time('test1');
var str = '';
for (var i = 0; i < intns; i++) {
if (str.length % 2 === 0) {
str += (i % 2 == 0) ? 's' : 'z';
}
else {
str += (i % 2 == 0) ? 'a' : 'b';
}
}
console.timeEnd('test1');
console.log('str len: ' + str.length + ' ' + str[0] + str[intns - 1])
console.log(`\n`)
console.time('test2');
var count = 0;
for (var i = 0; i < intns; i++) {
if (count % 2 == 0) {
count += (i % 2 == 0) ? 1 : 2;
}
else {
count += (i % 2 == 0) ? 3 : 4;
}
}
console.timeEnd('test2');
console.log(`sum: ${count}`)
console.log(`\n`)
console.time('test3');
var array = [];
for (var i = 0; i < intns; i++) {
array.push((i % 2 == 0) ? 's' : 'z');
}
console.timeEnd('test3');
console.log(`array len: ${array.length} ${array[intns - 1]}`)
console.log(`\n`)
console.time('test4');
var obj = {};
for (var i = 0; i < intns; i++) {
obj['s' + i] = (i % 2 == 0) ? 'a' : 'b';
}
console.timeEnd('test4');
console.log(`obj1: ${obj['s' + (intns - 1)]}`)
console.log(`obj2: ${obj['s' + 0]}`)
console.log(`\n`)
console.time('test Map');
var objMap = new Map();
for (var i = 0; i < intns; i++) {
objMap.set('s' + i, (i % 2 == 0) ? 'a' : 'b');
}
console.timeEnd('test Map');
console.log(`obj1: ${objMap.get('s' + (intns - 1))}`)
console.log(`obj2: ${objMap.get('s' + 0)}`)
В статье совсем правильная вводная. Это не совсем новый язык, никто не будет писать на wasm
wasm это в первую очередь бинарный формат который должен заменить asm.js, с нормальной работой с памятью и т.д. Вы пишите код на любой языке который поддерживает LLVM, компилируете код в wasm и получившийся модуль подключаете как любой другой скрипт
По этому примеры не несут никакого особого смысла, всё что работало для asm.js, будет работать и для wasm
У wasm есть человеко читаемое представление, но и там смотреть особо не на что:
Всё так и есть, не поспорить
Но async-await всё равно удобные. Удачно удалось сократить один модуль на промисах, переписав его на async-await, на 40%, и добавлять в него новый функционал стало проще и приятнее ^__^
В примере с new Array(10000) смысл ускорения не в том, что аллокаций нет, а в том, что массив заполнен и в цикле на 100000 итераций данные берутся уже готовые без вычислений
Я, для чистоты эксперимента, привела пример кода когда этот «недостаток» исключен, чтобы показать, что динамическое добавление в объект снижает производительность, но совершенно не критично, чтобы помнить об этом
Large же рассуждает и вовсе про сферические оптимизации в вакууме, и даже не привел ни строчки проблемного кода, который в реальный проект бы вносил тормоза. Упоминает только про домохозяек, хотя мог бы как истинный мужик доказать делом кодом
Поэтому прощу прощения, я бы с удовольствием обсудила реальные проблемы деоптимизаций, а не проблемы с недостатком мастерства или проблемы алгоритмов
Когда рассуждения на таком уровне идут, мне всегда вспоминается история как компания вложила много денег и времени чтобы ускорить код на golang v1.4, ничего путного не получилось, а потом вышел golang 1.5 и всё ускорилось само собой в 28 раз
Все так, но не для всех задач этого достаточно. При написании парсеров или игровой логики прийдется думать о том как выделяется память и куда расходуются циклы процессора.
Это не про убийц оптимизации, а про плохие алгоритмы
Те или иные оптимизации не означает написать for(var i = 0, l = arr.length; i < l; i++) {...}, это означат уменьшить выделение памяти, оптимизировать работу путем линейного выделения памяти, уменьшить количество вызовов и т.д.
И снова вы про плохие алгоритмы, а не про «убийц оптимизаций» в рамках статьи
покажите код, давать результаты тестирования в абсолютных значениях и без кода нет смысла. динамически менять свойства объекта это моветон, а не удобство, программист ожидает одну форму объекта, а у вас приходит другая так как вы где-то динамически что-то поменяли.
Проверим на 100000 итераций, попутно с вариантами для Map и Set:
time for fiboJsMemoDynamicObj: 160.85888671875ms
time for fiboJsMemoArray: 112.782958984375ms
time for fiboJsMemoMap: 470.0009765625ms
time for fiboJsMemoSet: 175.534912109375ms
fiboJsMemoResult: 1100000
fiboJsMemoArrayResult: 1100000
fiboJsMemoMapResult: 1100000
fiboJsMemoSetResult: 1100000
Разница между динамическим добавлением свойств и отсутствием всего 48-100мс
То о чем вы говорите, это снова про плохие алгоритмы и плохо продуманную архитектуру приложения. Это можно отнести к совершенно любому языку, даже с типизацией и отличным компилятором
А вся статья (эта и оригинальная) совершенно не про плохие алгоритмы
И таким программистам просто необходимо заморачиваться на даже 10% прирост производительности
Точно необходимо? Создатели AAA игр с вами не согласны, создатели http://slither.io/ с вами не согласны и т. д.
Вот вы потратили 90% времени разрабатывания вашей игры выискивая оптимизации для специфичной логике работы браузера, чтобы выжать fps на 10% больше, через неделю выходит оптимизатор который изменил логику работы и вектора больше не являются проблемой и ускорились на 30%, в обоих случаях это внесло 3.5% к результирующей производительности. А потом выясняется, что другие браузеры и вовсе по другому ведут себя с этой логикой.
И в итоге игра не готова, и ваши оптимизационные хаки оказались не так хороши
Вы ведь наверняка поняли о чем статья. Браузерные хаки ускоряющие не нужны, которые приводили к деоптимизации, а не то, что теперь можно плохие алгоритмы использовать, а v8 за вас все разгонит
С вашим нет я не соглашусь. Для UI нет, для игр и вычислений — да. Каждому свое.
То, что вы пишете на нем сложным путем, не делает его сложным и медленным для нормального использования (и игры и вычисления сюда входят)
в любом случае это уже свыше 20% запустите это в цикле и будет вам счастье
Это и было в цикле на 1000000 итераций. Выигрыш в 40мс на 1кк итераций — это не та «награда», которая компенсирует неудобство при написании js кода
Вы так и не поняли про что статья, то что вчера было медленным, завтра будет в 50 раз быстрее без вашего вмешательства. И не факт, что вы закончите проект раньше, чем выйдут новые оптимизации
Вот так как раз делать нельзя так как создаются новые скрытые классы для этих объектов и потери производительности значительны.
Именно так, и я проверила как это влияет на производительность, вместо 140мс, код выполнился за 180мс, добавляла 20 свойств динамически
Вы теряете суть и уходите в крайности. Вспоминать что у const и let были проблемы в рамках этой статьи странно. Генераторы тоже оптимизируются, как и async-await
Function is optimized by TurboFan: exampleFunction
Может получится так, что пока вы скрупулезно разбираетесь с тем какой тут нужен хак для ускорения, оптимизатор обгонит вас, а вы останетесь с ворохом знаний которые уже не актуальные и не будут актуальны
Куда важнее понимать принципы программирования в целом, чем изучать устаревшие оптимизации
Я понимаю вашу позицию, но не могу с ней согласиться
Код может оптимизироваться и так и эдак но работать совершенно с разной скоростью
Даже на самом быстром в мире языке можно написать код, который будет тормозить, и найдется тот, кто напишет его еще более медленным способом
Есть всего 3-5 простых некритичных правила, чтобы js-код не страдал потерей производительности:
1. Не переназначать переменные другим типом
2. Мегаморфизм функций
3. Не добавлять динамически свойства в объект
4. for быстрее forEach
5. Большое количество конкатенаций мелких строк (например, посимвольно) ведет к перерасходу памяти
Решение:
1. использовать const
2. редкое явление
3. потери производительности незначительны
4. использовать for..of
5. использовать arr.push вместо +=
Нужно понимать, как работает vm
Не нужно, vm это черный ящик, сегодня он так работает, завтра по другому
чтоб его ускорить приходится расписывать его некрасиво и дублировать конструкции
Раньше делали inline asm вставки в С код, сейчас чтобы сделать inline вставку, которая будет быстрее, чем clang заоптимизирует, настолько сложно, что этим мало кто занимается
Вы предлагаете заниматься тем же для js, ускорять то, что не внесет даже 0.1% в итоговую производительность, а может даже замедлит
Это всё интересно (знать про внутреннее устройство, про оптимизации, про ускоряющие хаки), но нужен взгляд и с другой стороны
Сейчас парадокс языка в том, что красивый код обычно означает медленный код
Наоборот, именно сейчас можно писать компактный, красивый, с async-await код, который будет быстрым, который удобно писать и понимать
Чтобы упростить задачу, у php-fpm снизьте до 1 server-start (и 0 чилдов), потому что у вас в 5 раз больше php обработчиков (которые работают как треды, а не как воркеры), а результат всего на 23% лучше, что говорит не в пользу php
Вы закрыли соединение до того, как промисы успели обратиться к базе. Поэтому они выкидывают сообщения об ошибках, а не тестируют соединение. А вот выкидывать сообщения об ошибках уже более дорогая операция, чем соединение
https://habrahabr.ru/post/320670/#comment_10039552
Тесты в цикле нельзя просто прогнать, нужно еще результат запомнить и прочитать его после цикла, иначе оптимизатор просто выкинет половину из цикла, или вовсе схлопнет цикл
Из статьи видим, что php это делает более агрессивно чем js, достаточно добавить немного «логики» в вычисления и php уже отстаёт
Автор всё равно сравнивает 5 тредов php-fpm против 1-го в ноде
Нужно либо ноду в кластере запускать, либо у php-fpm дефолтные настройки снизить
https://habrahabr.ru/post/320670/#comment_10039552
Нужно либо ноду в кластере запускать, либо у php-fpm дефолтные настройки снизить
https://habrahabr.ru/post/320670/#comment_10039552
node 7.3.0
php 7.1.1
На счет веб-сервера. У php-fpm не указаны настройки пула, по умолчанию у него 5 тредов
У ноды естественно 1
Либо у php надо понизить до 1, либо ноду как кластер запускать:
Но всё равно учитывая как взялись за php7, рано или поздно это может случиться
wasm это в первую очередь бинарный формат который должен заменить asm.js, с нормальной работой с памятью и т.д. Вы пишите код на любой языке который поддерживает LLVM, компилируете код в wasm и получившийся модуль подключаете как любой другой скрипт
По этому примеры не несут никакого особого смысла, всё что работало для asm.js, будет работать и для wasm
У wasm есть человеко читаемое представление, но и там смотреть особо не на что:
Но async-await всё равно удобные. Удачно удалось сократить один модуль на промисах, переписав его на async-await, на 40%, и добавлять в него новый функционал стало проще и приятнее ^__^
Я, для чистоты эксперимента, привела пример кода когда этот «недостаток» исключен, чтобы показать, что динамическое добавление в объект снижает производительность, но совершенно не критично, чтобы помнить об этом
Large же рассуждает и вовсе про сферические оптимизации в вакууме, и даже не привел ни строчки проблемного кода, который в реальный проект бы вносил тормоза. Упоминает только про домохозяек, хотя мог бы как истинный мужик доказать
деломкодомПоэтому прощу прощения, я бы с удовольствием обсудила реальные проблемы деоптимизаций, а не проблемы с недостатком мастерства или проблемы алгоритмов
Когда рассуждения на таком уровне идут, мне всегда вспоминается история как компания вложила много денег и времени чтобы ускорить код на golang v1.4, ничего путного не получилось, а потом вышел golang 1.5 и всё ускорилось само собой в 28 раз
Если бы функция была deopt, то даже дикие ухищрения с алгоритмом вам не помогли бы ее разогнать, только хаки для браузера
Можно сортировку делать пузырьком и приговаривать «Ах этот v8, не разогнал мой код»
Прощу прощения, не могу больше поддержать разговор на эту тему
Нужно писать эффективные алгоритмы
Просто к теме убийц оптимизаций это не относится
И снова вы про плохие алгоритмы, а не про «убийц оптимизаций» в рамках статьи
Вот код из соседней темы про wasm:
https://habrahabr.ru/company/ruvds/blog/319834/#comment_10020032
Усложним немного код оригинала, чтобы было еще очевиднее факт динамического добавления в объект:
Проверим на 100000 итераций, попутно с вариантами для Map и Set:
Код целиком: http://codepen.io/anon/pen/vgZoWe
Разница между динамическим добавлением свойств и отсутствием всего 48-100мс
То о чем вы говорите, это снова про плохие алгоритмы и плохо продуманную архитектуру приложения. Это можно отнести к совершенно любому языку, даже с типизацией и отличным компилятором
А вся статья (эта и оригинальная) совершенно не про плохие алгоритмы
Вот вы потратили 90% времени разрабатывания вашей игры выискивая оптимизации для специфичной логике работы браузера, чтобы выжать fps на 10% больше, через неделю выходит оптимизатор который изменил логику работы и вектора больше не являются проблемой и ускорились на 30%, в обоих случаях это внесло 3.5% к результирующей производительности. А потом выясняется, что другие браузеры и вовсе по другому ведут себя с этой логикой.
И в итоге игра не готова, и ваши оптимизационные хаки оказались не так хороши
Вы ведь наверняка поняли о чем статья. Браузерные хаки ускоряющие не нужны, которые приводили к деоптимизации, а не то, что теперь можно плохие алгоритмы использовать, а v8 за вас все разгонит
То, что вы пишете на нем сложным путем, не делает его сложным и медленным для нормального использования (и игры и вычисления сюда входят)
Это и было в цикле на 1000000 итераций. Выигрыш в 40мс на 1кк итераций — это не та «награда», которая компенсирует неудобство при написании js кода
Вы так и не поняли про что статья, то что вчера было медленным, завтра будет в 50 раз быстрее без вашего вмешательства. И не факт, что вы закончите проект раньше, чем выйдут новые оптимизации
Нет
Вы не это говорите, перечитайте ваши комментарии
Именно так, и я проверила как это влияет на производительность, вместо 140мс, код выполнился за 180мс, добавляла 20 свойств динамически
Вы теряете суть и уходите в крайности. Вспоминать что у const и let были проблемы в рамках этой статьи странно. Генераторы тоже оптимизируются, как и async-await
Может получится так, что пока вы скрупулезно разбираетесь с тем какой тут нужен хак для ускорения, оптимизатор обгонит вас, а вы останетесь с ворохом знаний которые уже не актуальные и не будут актуальны
Куда важнее понимать принципы программирования в целом, чем изучать устаревшие оптимизации
Даже на самом быстром в мире языке можно написать код, который будет тормозить, и найдется тот, кто напишет его еще более медленным способом
Есть всего 3-5 простых некритичных правила, чтобы js-код не страдал потерей производительности:
1. Не переназначать переменные другим типом
2. Мегаморфизм функций
3. Не добавлять динамически свойства в объект
4. for быстрее forEach
5. Большое количество конкатенаций мелких строк (например, посимвольно) ведет к перерасходу памяти
Решение:
1. использовать const
2. редкое явление
3. потери производительности незначительны
4. использовать for..of
5. использовать arr.push вместо +=
Не нужно, vm это черный ящик, сегодня он так работает, завтра по другому
Раньше делали inline asm вставки в С код, сейчас чтобы сделать inline вставку, которая будет быстрее, чем clang заоптимизирует, настолько сложно, что этим мало кто занимается
Вы предлагаете заниматься тем же для js, ускорять то, что не внесет даже 0.1% в итоговую производительность, а может даже замедлит
Это всё интересно (знать про внутреннее устройство, про оптимизации, про ускоряющие хаки), но нужен взгляд и с другой стороны
Наоборот, именно сейчас можно писать компактный, красивый, с async-await код, который будет быстрым, который удобно писать и понимать