Comments 18
При сравнении SHA-256 была допущена неточность.
Для Node.js вы делаете await
в цикле, а для GoLang wg.Wait();
после цикла. Если вы измеряете скорость параллельного вычисления, то имеет смысл в Node.js сделать с помощью Promise.all
Спасибо за интерес к статье и дельное замечание.
К счастью влияние на абсолютный результат - минимальны (перепроверил).
И в принципе логично, потому что CPU-bound работа идёт просто в том же потоке, но если бы модуль crypto имел асинхронные интерфейсы, то всё бы действительно выполнялось параллельно. А так async/await вешать на обычную функцию, пускай она и будет даже иметь обёртку в виде:
function hash(data, algo) {
return new Promise(resolve => {
resolve(crypto.createHash(algo).update(data).digest('hex'));
});
}
Всё равно будет выполняться синхронно. Через node-gyp можно писать на C/C++ как раз модули, где и реализовать асинхронный интерфейс для функций хеширования (на npm даже вроде есть готовые пакеты).
Кстати, WASM - есть WASM, ему неважно на каком языке писали, поэтому у компилятора для Go на WASM тоже есть подводные камни.
Так что лучший перформанс можно получить, написав нативные модули к Node.js (например, с помощью node-gyp).
Да, готовые пакеты есть (скорее всего речь идет о crypto-async).
Что касается Go -> wasm, то с подводными камнями пока не знаком. Как раз для начала "раскопок" в этом направлении и была написана статья.
Кайфанул при прочтении, большое спасибо :)
Второй "забег", очевидно, не стоит принимать во внимание - js там просто складывал два числа, а остальные предварительно приводили строку к числу.
4 и 5 - сравнение нативных реализаций, написанных скорее всего на плюсах. Это не сравнение языков.
Итого остается 1 и 3. Ну с первым всё понятно, нода рулит в io. А насчет третьего - может быть, оптимизирующий компилятор v8 недостаточно прогрел код?
А почему не рассматривался 4-й вариант: написать Native Addon для Node.js использую https://nodejs.org/api/n-api.html#node-api ?
Даже если поблизости нет C или С++ программиста, то вроде бы в Go можно сделать библиотеку, экспортирующую функции в C стиле, и использовать их с Node-API
gif мешают усваивать материал.
Автор сделал ерунду. Первые два примера вообще ни о чем. А четвертый и пятый пример про хеш функции скорее всего сводится в вызову сишного кода под капотом. Только про фибоначи нормальный пример.
Простите за оффтоп, но для себя открыл, что на m1 100000-е число Фибоначчи, считается в среднем за 74ms.
Методика замера:
const timeDiff = (begin, end) => (end - begin) / 1000000n;
const main = () => {
const begin = process.hrtime.bigint();
let num = 100000n
let a = 1n, b = 0n, temp;
while (num > 0n) {
temp = a;
a += b;
b = temp;
num -= 1n;
}
const end = process.hrtime.bigint();
console.log(b, '\n');
console.log('Время:', timeDiff(begin, end), ' ms.');
};
main();
Интересное исследование, пару месяцев назад делал аналогичное для Node.js+Rust WASM практически для тех же задач. Главная проблема с вызовом функций из WASM это оверхед при передаче/получении аргументов и результатов функций, поэтому задачи в стиле сложить два числа выполняются Node.js быстрее. В случае с хешом, Node.js под капотом использует плюсы и тут вряд-ли что-то можно оптимизировать.
Использование Golang для разработки Node.js приложений (Node.js: In Go We Trust)