Всегда ли библиотеки на С быстрее чем JS

от автора

Не так давно была статья о выходе js-yaml 2.0.0, который был полностью написан на JS и при этом работал весьма быстро. И только недавно я узнал, насколько же все хорошо на самом деле :). А началось все с того, что знакомый пожаловался на руби, который долго парсил 7-мегабайтный yaml-файл. Это было довольно странно, потому что руби использует биндинги к libyaml. Мы написали несколько примитивных тестов для руби с питоном, и получили такие результаты, что я заподозрил ошибку.

Тогда создал тему на LOR, там нашли пару косяков и добавили примеров с других языков. Картину мира это улучшило, но не сильно. JS подозрительно быстр. Результат ниже, а в конце пара замечаний.

Сразу оговорюсь, что текущие примеры не являются грамотными тестами. Там не учитывается много вещей, которые влияют на точность. Зато просто, дешево, сердито, и хватает для качественной оценки. Когда исходные данные отличаются на порядок, то ошибка в 2 раза мало кого волнует — разницу вы все равно увидите, и поймете что она большая.

Тестовый сид лежит на гитхабе gist.github.com/anonymous/5028302

Поехали

кросафчег js-yaml (чистый JS):

time node -e "var yaml=require('js-yaml'), text=require('fs').readFileSync('data.yml', 'utf-8'); yaml.load(text);"  real	0m0.984s user	0m0.940s sys	0m0.040s 

node.js & libyaml:

time node -e "require('libyaml').readFileSync('data.yml');"  real	0m3.424s user	0m3.300s sys	0m0.136s 

python & libyaml:

time python -c "import yaml; from yaml import CLoader as Loader; yaml.load(open('data.yml'),Loader=Loader)"  real	0m5.530s user	0m5.268s sys	0m0.212s 

perl & libyaml:

time perl -MYAML::XS -e 'YAML::XS::LoadFile "data.yml"'  real	0m0.484s user	0m0.456s sys	0m0.024s 

php & libyaml:

time php -r 'yaml_parse_file("data.yml");'  0,49s user  0,04s system  99% cpu  0,537 total 

ruby 2.0 & libyaml:

time ruby -r psych -e "Psych.load_file 'data.yml'"  6.34s user 0.09s system 99% cpu 6.494 total 

ruby 2.0 & syck:

time ruby -r syck -e "Syck.load_file('data.yml')"                            0.87s user 0.02s system 96% cpu 0.920 total 

JSON node.js (просто для сравнения)

time node -e "var text=require('fs').readFileSync('data.json', 'utf-8'); JSON.parse(text);"  real	0m0.265s user	0m0.152s sys	0m0.040s 

Оригинал живет и пополняется на github.

Итого

А имеем мы в итоге любопытный результат:

  • кривые биндинги могут запороть весь профит от бинарного кода
  • js-yaml даже при том, что не до конца оптимизирован, всего лишь в 2-3 раза уступает самым удачным биндингам (perl/php)

И еще — даже если вы во внешней библиотеке очень быстро все посчитаете, то импорт данных в runtime не бесплатный. Особенно для динамических языков. Может так получится, что вынос кода в компилированные библиотеки потеряет смысл.

Возвращаясь к JS, в среднем по больнице получается, что при правильном подходе потребность в бинарном коде невелика. А чтобы постичь глубины мудрости, нужно посмотреть выступление Вячеслава Егорова youtu.be/tCG0aPNvkTs об оптимизациях в v8.

PS. По моим прикидкам, js-yaml можно ускорить еще раза в 2 или больше. Если кто-то хочет набить руку на оптимизациях JS — обращайтесь 🙂

ссылка на оригинал статьи http://habrahabr.ru/post/170823/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *