Как стать автором
Обновить
16
0

Пользователь

Отправить сообщение
Всем известно что у пхп массивы довольно медленная часть, поскольку они универсальные. По этой причине были созданы другие структуры данных, а именно специальные классы.

Любой кто когда либо работал с SPL знает, что они ужасны.

Далее было сказано, что " если бы были просто массивы (не ассоциативные), то node был бы еще быстрее чем php". Было такое утверждение? Было.

Разницы между 7672.947ms и 6663.210ms можно сказать вообще нет, поэтому я написала про обычные массивы или про вычисление каких-нибудь данных, где разница была бы заметнее.

Вы переписали код ноды так, как более правильно писать под ноду. Было? Было.

Я переписала код так, как правильно писать под js, ведь тянуть php практики в js не правильно по многим причинам, и это ни для кого ни секрет. «new Map» вместо ассоциативных массивов рекомендуют использовать все, в том числе и создатели node. Да если уж на то пошло, вообще использовать es6 рекомендуют по полной.

Если у php есть что-то подобное, то никто не запрещает вам переписать php-пример.
Но именно [] в php7 и есть лучший выбор, потому что на него был сделан основной упор оптимизаций по сравнению с php5.
Как только мы об этом узнали, мы перевели все сайты на php7-fpm (давно, еще в бете) и отлично он держит ~2.652.376 хитов в день. На ноду переходить вообще не вижу смысла, но это не отменяет того факта, что на js надо писать правильно.

И хотя я знала, что кто-то обязательно придерется к Map, я всё-таки сделала упор на new Map только по той причине, что он тут правильнее по смыслу, es6 все дела. Можно было бы и без него, достаточно всего 1 строчки кода в оригинальном примере после цикла:

m = m.slice();

И код бы ускорился в 2 раза, и так же бы обогнал php-версию, без каких-либо новых структур данных

Вы бы тоже сказали, что это читерство? Хотя все кто пишут на js знают, что если уж вы начали массив заполнять ассоциативными данными, то это будет череда скрытых классов, которые работают крайне не эффективно и после заполнения надо слить их в новый единый объект. А оправдывать тем фактом, что якобы не все про это знают, не говорит о скорости языка ни как.

А значит _честно_ будет использовать не числовые массивы, а именно классы из SPL. Двусвязный список или ФиксМассив, не суть.
Мне вот интересно, это я действительно настолько непонятно выразился

Вместо рассуждений, могли бы просто взять и привести правильный пример. Но у вас не получилось бы, потому что в SPL ни один из них не делает то, что нужно в данном случае. Или если делает, то очень заморочено, и нужно писать обвязку. И всё равно это было бы медленнее, чем [] в php7.
Не, ну это не совсем честно. Вы ведь код под ноду оптимизировали?

Что не честно? Вы процитировали цитату из части про «если бы», о чем речь?
Я вообще ничего не оптимизировала, я написала как будет правильно под ноду.
а теперь внимание, шок (у меня лежала старая версия от 2015 года)
Этот, немного странноватый, тест наверное единственный случай когда старая нода оказалась быстрее, так как в реальном коде все наоборот.

Причешем немного код на php, и добавим 2 missed счетчика, чтобы была интрига у кого рандомайзер лучше:
php код
<?
$t1 = microtime(true);

$m = [];
// fill array with random keys, 3chars len each with 0..255 char code
$mlen = (256 * 256 * 256) / 16; // size of array, part of possble amount of keys to test key missing
for ($i = $mlen; $i > 0; $i--)
    $m[chr(rand(0, 255)).chr(rand(0, 255)).chr(rand(0, 255))] = true;

$t2 = microtime(true);

// count miss
$missed = 0;
$missed2 = 0;
for ($a = 0; $a < 255; $a++)
    for ($b = 0; $b < 255; $b++)
        for ($c = 0; $c < 255; $c++)
            if (!isset($m[chr($a).chr($b).chr($c)]))
                if (rand(0, 2) % 2 == 0)
                    $missed++;
                else
                    $missed2++;

$t3 = microtime(true);

echo 'filling: ' . number_format($t2 - $t1, 6, '.', '') * 1000 . 'ms' . PHP_EOL;
echo 'counting: ' . number_format($t3 - $t2, 6, '.', '') * 1000 . 'ms' . PHP_EOL;

echo PHP_EOL . $missed . '; ' . $missed2 . '; ';


В js коде (вдруг кому интересно):
1. В функция rand не хватает «min + 1»
2. Для подобных целей вместо ассоциативного массива нужно использовать Map
3. Проверять на отсутствие значения лучше так «if (!arr[key])»
4. fromCharCode можно в краткой форме записать «String.fromCharCode(rand(0, 255), rand(0, 255), rand(0, 255))»
5. В начале всех js файлов лучше писать 'use strict'; — избавит от множества проблем.
6. Для вычисления времени выполнения удобно использовать «console.time('metka')», хотя есть и более точный вариант «performance.now()»

Переписанный пример на js:
код js
'use strict';

function rand(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

console.time('filling')

var m = new Map();
// fill array with random keys, 3chars len each with 0..255 char code
var mlen = (256 * 256 * 256) / 16; // size of array, part of possble amount of keys to test key missing
for (var i = mlen; i > 0; i--) {
    m.set(String.fromCharCode(rand(0, 255), rand(0, 255), rand(0, 255)), true);
}

console.timeEnd('filling')

console.time('counting')
// count miss
var missed = 0;
var missed2 = 0;
for (var a = 0; a < 255; a++) {
    for (var b = 0; b < 255; b++) {
        for (var c = 0; c < 255; c++) {
            if (!m.get(String.fromCharCode(a, b, c))) {
                if (rand(0, 2) % 2 === 0)
                    missed++;
                else
                    missed2++;
            }
        }
    }
}
console.timeEnd('counting')

//console.log(`\n${missed}; ${missed2}; `);
console.log('\n' + missed + '; ' + missed2 + ';'); // for node v0.12.7



И, соответственно, результат:

PHP 7.1.4 (cli):
>php test.php
filling: 788.352ms
counting: 7672.947ms

10387458; 5189704;


node v0.12.7:
>node test.js
filling: 616ms
counting: 7304ms

10393087; 5195409;


node v7.9.0:
>node test.js
filling: 533.590ms
counting: 6663.210ms

10386734; 5190004;


Результат уже более предсказуемый, если бы были просто массивы (не ассоциативные), то node был бы еще быстрее чем php, или вычисления какие с этими данными.
Скорее всего минусы не за комментарий в целом, а за упоминание JSDoc, который многие не любят, особенно в противовес наглядных типов, которые так и так пишутся, а jsdoc еще надо заставить себя написать
То есть функция которой требуется документация хуже чем которой не требуется, даже если они делают одно и тоже.
Хотя нет, если написать именно как iShatokhin предлагает:
const await1 = delay(500)
const await2 = delay(500)
let arr = [await await1, await await2]

await array: 501.792ms
Promise.all: 500.836ms

То всё работает, но для второго await остается Unhandled promise rejection
Промисы были инициализированы выше по коду (сейчас в состоянии pending), т.ч. получается параллельно

Природа event-loop не даст войти внутрь промиса пока не появится в коде «свободное окно» вроде then/await или отсутствие других вычислений, пока они именно что в ожидании на выполнение

async function delay(time) {
    return new Promise(resolve => setTimeout(resolve, time))
}

async function main() {
    try {
        console.time('await array')
        let arr = [await delay(500), await delay(1000)]        
        console.timeEnd('await array')
    
        console.time('Promise.all')
        arr = await Promise.all([delay(500), delay(1000)])
        console.timeEnd('Promise.all')
    }
    catch(err) {
        console.log(err)
    }
}

main()

>node index.js
await array: 1501.689ms
Promise.all: 1000.757ms
Для массовой обработки:
Для windows iCatalyst: https://github.com/lorents17/iCatalyst
Для osx ImageOptim: https://imageoptim.com/mac

Для сервера есть много вариантов, но самые эффективные это последнии разработки в этой области (2014 и 2013 года соответственно):
mozjpeg для сжатия jpg (от mozilla)
zopflipng для сжатия png (от google)

Жмут очень хорошо, по сравнению со старыми способами могут на 3-5% лучше сжать для jpg и 10-15% для png.

От гугля есть еще Guetzli для jpg, но сжимает оооочень (прям очень приочень) долго, а результат не сильно лучше чем у mozjpeg, который работает почти мгновенно.
Нельзя просто написать «Не используйте, это медленно, вот цифры показывающие что в 2600 раз медленнее» и надеяться, что все молча это схавают.

Надоело смотреть на то, как никто не хочет отвечать за свои слова «ой, я не то имел ввиду, ой, меня не так поняли, ой я говорил про сферическое фп в вакуме».
Продолжать особо не о чем, потому что я написала изначальный комментарий только чтобы мимо проходящие посетители не ужаснулись вашими псевдо-огромными цифрами и не послушали вашего совета.
Особенно на фоне того, что, как выяснилось позже, вы осмысленно их пытались ввести в заблуждение.
При этом совет про «профилирование» вполне себе разумный.
То есть это не вы рекомендовали не использовать Object.assign, потому что якобы он в тысячи раз медленнее в reduce?

Мы с вами говорим об одном и том же, но разными словами. Даже выводы одни и те же.
Ну да, получается мы об «одном и том же», я привожу данные что падения производительности нет, а вы утверждаете что в 2600 раз медленнее. Ну да, видно что вывод один в один.
Именно поэтому надо избегать Object.assign в reduce, потому что это не тру вэй ФП/чистые_функции, хотя производительность такая же как с вариантом с for-ом?
… так бы я написала, если бы то что вы написали имело смысл.

Какая разница с точки зрения иммутабельности в коде:
Object.assign({}, o, [key]: key }) (медленный вариант)
Object.assign(o || {}, [key]: key }) (быстрый вариант)
Если в обоих случаях «o» это внутренний объект reduce?

Вот ответ:
Код в обоих случаях делает одно и тоже, с одинаковой степенью иммутабельности, никакой разницы нет, только один искусственно тормозной, а второй очень быстрый.

Еще говорят, что у меня женская логика…

Оффтоп
Я уже кажется с вами раньше дискутировала и уже приходила к выводу, что это бесполезно.
Наверняка найдется тот, кто поймет ваши хитросплетения мыслей, но у меня на это банально нет желания.
Вот ваши слова:
Касательно производительности. Тут мне кажется стоило бы избегать return arr.concat(el) и return Object.assign(obj, {...}) в reducer-ах в пользу мутабельных вариантов, т.к. разница может быть более чем тысячекратной (проверял на object.assign в reduce-цикле). ...2600-кратное ускорение.

И вы приводите пример кода, который специально делает много лишней работы (раз вы говорите что это не опечатка).

Потом я привожу исправленный код, и выясняется, что никаких проблем с производительностью нет, Object.assign прекрасно работает в reduce-цикле без потери производительности.
Эээ…
Клонировать внутренний объект 10000 раз, только лишь для того, чтобы в результате забрать финальный клон — с трудом верю, что это именно то, что вы хотели сделать.
Именно это и делал ваш код (хотя ваш вариант с for делает другое).

Но если опечатки нет, и это действительно была ваша цель, то что-то вы не то делаете, к производительности js это ни как не относится, и речи про 2600-кратное ускорение тем более не идет.
Ваш код:
const keys = []; for(let i = 0; i < 100000; i += 10) keys.push(i); 

console.time('mutable');
const obj1 = {};
for(let key of keys) obj1[key] = key;
console.timeEnd('mutable');

console.time('reduce');
const obj2 = keys.reduce((o, key) => Object.assign({}, o, </b> [key]: key }), {});
console.timeEnd('reduce');

Результат:
mutable: 3.034ms
reduce: 21646.400ms


Исправленный код, в котором исправлена «опечатка»:
const keys = []; for(let i = 0; i < 100000; i += 10) keys.push(i); 

console.time('mutable');
const obj1 = {};
for(let key of keys) obj1[key] = key;
console.timeEnd('mutable');

console.time('reduce');
const obj2 = keys.reduce((o, key) => Object.assign(o || {}, { [key]: key }), {});
console.timeEnd('reduce');

Результат:
mutable: 3.084ms
reduce: 11.763ms


Ускорение всего лишь в 4 раза, поэтому можно не отказываться от Object.assign, если кому-то с ним удобнее/нагляднее.

Почему так получилось?
Вот эта строка:
Object.assign({}, o, { [key]: key })

Исправлена на такую:
Object.assign(o || {}, { [key]: key })

Из документации:
Метод Object.assign() копирует из исходных объектов в целевой объект

Поэтому хоть первый вариант тоже корректный, но он заставляет бесконечно клонировать объект «o» в новый пустой (каждый раз который увеличивается в размерах), вместо того, чтобы просто добавить новый ключ в уже существующий «o».
Это как раз не шутка)

«В марте 2016 года корпорация Intel объявила двухшаговый цикл Тик-Так (принятый в 2007 году) устаревшим, и они переходят на трехступенчатую модель «process-architecture-optimization».»

Первый процессор на архитектуре под кодовым названием «Cannonlake» с использованием этой трехшаговой модели планируется к выпуску в первом квартале 2018 года
Приведу пример, для чего может быть полезен wasm
Сейчас мы делаем standalone веб-приложение по распознанию и анализу японского текста с изображений. Распознание производится с помощью tessaract, который через emscripten был скомпилирован в asm.js код.



Распознание в хроме без поддержки asm.js: 9.17 секунды
Распознание в фаерфоксе с поддержкой asm.js: 3.19 секунды
Это не считая времени на инициализацию 2.8 мегабайт js кода

Теоретически, при появлении wasm результат будет 1.2 секунды в любом браузере, а инициализация модуля будет быстрее (и весить он будет меньше).

Не нужно ничего качать и устанавливать, достаточно зайти на сайт и быстренько распознать интересующий кусок текста, и с применением того же метода можно тут же увидеть анализ текста:



Поэтому на данном этапе можно сказать, что wasm это не замена js, не работа с dom (сам dom к js имеет слабое отношение, поэтому ускорение js не дает ускорение dom), а дополнение к текущим возможностям, без которых было бы менее удобно.
Потому что wasm это лишь дальнейшее развитие идеи asm.js. Всё что работало для asm.js будет, на данный момент, работать для wasm

Поэтому ничего более сложного, чем уже есть на официальном сайте не требуется http://webassembly.org/getting-started/developers-guide/
Только собралась собирать тестовый стенд, как вы уже сами подтвердили, что php медленнее, хотя я и так об этом говорила уже

Если добавить к тестам логики, то php отстанет еще сильнее
node 7.3.0 vs php 7.1.1:
test1_node (str): 67.853ms 
test1_php (str): 83.961ms

test2_node (sum): 8.685ms 
test2_php (sum): 69.857ms

test3_node (array): 53.455ms 
test3_php (array): 63.453ms

«обогнал» так обогнал, только пятки видны.
При этом чем больше логики (то есть чем приложение больше приближено к реальному), тем слабее позиции php. Но можно и дальше закрывать на это глаза и прогонять «пустые» тесты без логики

Информация

В рейтинге
Не участвует
Откуда
Дания
Зарегистрирована
Активность