В этой статье решил выложить довольно интересные, на мой взгляд, результаты бенчмарка собственного производства. Данный бенчмарк создан с целью выяснить скорость работы нативных и bluebird-промисов.

image


Исходный код бенчмарка (вариант №1):

var Promise = require('bluebird'); // Если хотите проверить скорость работы нативных промисов то необходимо закомментировать данную строку.
var crypto = require('crypto');
var iterations = 1000000;
var start = Date.now();
var arrayPromises = [];
var promiseWrap = function () {
    return new Promise(function (resolve, reject) {
        crypto.randomBytes(256, (err, buf) => {
            if (err) reject(err);
            resolve(buf);
        });
    });
};
for(var i = 0; i < iterations; i++){
    arrayPromises.push(promiseWrap());
}

if(arrayPromises.length === iterations){
    Promise.all(arrayPromises).then(function (result) {
        var finish = Date.now()-start;
        console.log("Бенчмарк промисов выполнен!");
        console.log("Время выполнения "+finish/1000+" сек.");
    });
}


Исходный код бенчмарка (вариант №2):

var Promise = require('bluebird'); // Если хотите проверить скорость работы нативных промисов то необходимо закомментировать данную строку.
var crypto = require('crypto');
var iterations = 1000000;
var start = Date.now();
var arrayPromises = [];
var promiseWrap = function () {
  return new Promise(function (resolve, reject) {
      setTimeout(function () {
          resolve(Math.random(1));
      },0)
  });
};
for(var i = 0; i < iterations; i++){
    arrayPromises.push(promiseWrap());
}

if(arrayPromises.length === iterations){
    Promise.all(arrayPromises).then(function (result) {
        var finish = Date.now()-start;
        console.log("Бенчмарк промисов выполнен!");
        console.log("Время выполнения "+finish/1000+" сек.");
    });
}


Данный бенчмарк в качестве результата выводит время, за которое резолвятся все промисы. Результаты бенчмарка на моей машине:

Время выполнения:
Нативные промисы (вариант №1 node v6.4.0) — 19.808 сек.
Bluebird-промисы (вариант №1 node v6.4.0) — 9.654 сек.
Нативные промисы (вариант №1 node v6.5.0) — 19.957 сек.
Bluebird-промисы (вариант №1 node v6.5.0) — 9.723 сек.
Нативные промисы (вариант №2 node v6.5.0) — 10.61 сек.
Bluebird-промисы (вариант №2 node v6.5.0) — 2.208 сек.


Максимальное значение выделенной памяти (rss):
Нативные промисы (вариант №2 node v6.5.0) — 1282 Мб.
Bluebird-промисы (вариант №2 node v6.5.0) — 601 Мб.


Среднее значение выделенной памяти (rss):
Нативные промисы (вариант №2 node v6.5.0) — 368 Мб.
Bluebird-промисы (вариант №2 node v6.5.0) — 297 Мб.


Вывод: bluebird промисы работают быстрее нативных промисов в 2-5 раз, а так же требуют гораздо меньше оперативной памяти.

Если я в чем то ошибаюсь, то большая просьба сообщить в комментариях. Буду очень рад услышать от вас, какие либо поправки.

» Ссылка на библиотеку bluebird
Поделиться с друзьями
-->

Комментарии (27)


  1. kir_vesp
    31.08.2016 17:20
    +3

    Про то как V8 оптмизирует код почитайте. Ваш бенчмарк совершенно некорректен.


    1. ruslangavrilov
      31.08.2016 17:20

      Спасибо за комментарий. Напишите, пожалуйста корректный бенчмарк. Очень хочется посмотреть на грамотную реализацию.


      1. kir_vesp
        31.08.2016 18:01

        Минимально корректным будет бэнчмарк, в котором Вы в каждый промис передавали бы новую переменнную, для примера можно глянуть на бэнчмарки в репозитории.


    1. youlose
      31.08.2016 17:40
      +5

      Зря накинулись:
      http://programmers.stackexchange.com/questions/278778/why-are-native-es6-promises-slower-and-more-memory-intensive-than-bluebird


      1. kir_vesp
        31.08.2016 17:59

        За ссылку спасибо, аргументация хорошая. Убеждает.


  1. neoxack
    31.08.2016 17:20
    +2

    Абсолютно бесполезный бенчмарк. Тестировать промисы нужно под асинхронной нагрузкой.


    1. ruslangavrilov
      31.08.2016 17:21

      Можете привести пример?



    1. Iqorek
      31.08.2016 23:07

      Что даст «асинхронная нагрузка»? Завалит callback queue колбеками от асинхронных вызовов? На чистое время исполнения промисов, это не повлияет.


  1. igontarev
    31.08.2016 17:20

    впечатляет, а что на счет observble?


    1. Iqorek
      31.08.2016 23:08
      -2

      Object.observe? судя по всему он тоже написан на javascript и там тоже можно ожидать худших результатов, чем у аналогов.


  1. SDI
    31.08.2016 17:40

    Неделю назад был статья JavaScript Performance, базы данных и поиски «серебряной пули»: видеозаписи ТОП-5 докладов HolyJS 2016
    В ней есть видео на доклад Вячеслава Егорова, «Производительность JavaScript через подзорную трубу»
    В данном докладе объясняется почему данный бенчмарк некорректен.

    И вот хорошая статься Что браузеры делают с вашим JavaScript-кодом: об оптимизациях в JS-движках на примере V8


  1. ruslangavrilov
    31.08.2016 17:45

    Бенчмарк поправил. Сейчас более корректно?


    1. Boomburum
      31.08.2016 17:52

      Немного промахнулись ответом :) SDI вам тут ответили.


  1. Laney1
    31.08.2016 18:10
    +5

    рискну предположить, что разработчики v8 не стараются оптимизировать промисы, потому что для них это не критично. Какая разница, сколько миллисекунд будет потрачено в служебном коде, если в 99.5% случаев промису придется ждать ответ на веб-запрос? Но разработчику bluebird все равно респект


    1. jMas
      31.08.2016 19:37
      +1

      Иногда промисы используют например в анимациях:

      function show(element) {
        return new Promise(resolve => element.animate([
          { opacity: 0, transform: 'scale(.5)' },
          { opacity: 1, transform: 'scale(1)' }
        ], { duration: 250 }).onfinish = resolve).then(() => {
          element.style.opacity = 1;
        });
      }
      


      1. vintage
        31.08.2016 20:28
        +1

        В собственно анимации тут промисы явно не используются.


        1. jMas
          31.08.2016 21:47

          Более — они и в Ajax запросах, в популярных библиотеках, тоже явно не используются. Я просто привел пример, где производительность промисов может как то повлиять на конечный результат.


          1. vintage
            31.08.2016 23:31

            В данном случае один единственный промис не в состоянии как-либо повлиять на анимацию.


            1. jMas
              01.09.2016 11:32
              +1

              show(el).then(() => hide(el)).then(() => show(el)).then(() => expand(el))...;
              

              Например цепочка промисов. Чем больше задержка в промисах, тем дерганей будут переходы между анимациями. Но да, полагаю это не сильно существенно если промисы достаточно быстрые и доли секунды не заметны глазу.

              Но не всегда асинхонная функция асинхронна. Иногда функция (в зависимости от разных ситуаций) сама принемает решение: получить данные из стороннего источника или взять уже имеющиеся в кэше и отдать синхронно, но интерфейс все равно — промис. Тогда было бы не плохо получить данные максимально быстро. Не так ли?


    1. Shannon
      31.08.2016 20:18

      Стараются, по крайней мере движение есть
      node v6.3.1: 26.3 сек
      node v6.5.0: 16.5 сек

      Вообще на node 6.5.0 тест из статьи выдает такие результаты:

      Bluebird
      Время выполнения 14.876 сек.
      
      Native promise
      Время выполнения 16.519 сек.
      


      1. ruslangavrilov
        01.09.2016 07:40

        Странные результаты. У меня на node 6.5.0 совсем по другому. В статью добавил результаты, полученные при использовании этой версии.


        1. Shannon
          02.09.2016 03:55

          Первый вариант повторно

          $ node prom.js 
          Бенчмарк промисов выполнен!
          Время выполнения 14.426 сек.
          $ node prom.js 
          Бенчмарк промисов выполнен!
          Время выполнения 15.856 сек.
          $ node -v
          v6.5.0
          

          Второй вариант:
          $ node prom.js 
          Бенчмарк промисов выполнен!
          Время выполнения 2.7 сек.
          $ node prom.js 
          Бенчмарк промисов выполнен!
          Время выполнения 10.404 сек.
          


  1. vvadzim
    31.08.2016 20:33

    Так это не сюрприз для активных промисеров :) На сайте блюберда: http://bluebirdjs.com/docs/benchmarks.html


  1. Jabher
    01.09.2016 00:13

    Все корректно — Петька Антонов адово крутит перфоманс, и его реализация давным-давно известна за чудовищную эффективность. А вот почему его код не перенесли в v8 — для меня большой вопрос.


  1. hell0w0rd
    01.09.2016 01:03

    bluebird быстрее стандартных промисов, да и прочих реализаций промисов. Это факт.
    Но ваш тест, даже откинув остальные косяки, тестирует не промисы, а crypto.randomBytes. То, что происходит внутри промисов должно выполняться за константное время, чтобы протестировать непосредственно промисы.


  1. Andropolon
    01.09.2016 07:37
    +1

    Рекомендую еще сравнить расход оперативной памяти на промисы.
    Будете очень удивлены, особенно в Google Chrome.
    По нашим тестам, нативные промисы съели около 200 МБайт памяти на 100 000 вызовов.
    Bluebird — что-то около 10 Мбайт кажется.