Что делает Ruby медленным?

Руби медленно работает над некоторыми вещами. Но какие его части являются наиболее проблематичными?

Сколько сборщик мусора влияет на производительность? Я знаю, что у меня были времена, когда запуск сборщика мусора занимал несколько секунд, особенно при работе с библиотеками OpenGL.

Я использовал матричные математические библиотеки с Ruby, которые были особенно медленными. Есть ли проблема с тем, как Ruby реализует базовую математику?

Существуют ли какие-либо динамические функции в Ruby, которые просто невозможно реализовать эффективно? Если да, то как другие языки, такие как Lua и Python, решают эти проблемы?

Была ли проведена недавняя работа, которая значительно улучшила производительность?

Ответ 1

Рубика медленная. Но какие его части являются наиболее проблематичными?

Он выполняет "поздний поиск" для методов, чтобы обеспечить гибкость. Это немного замедляет его. Он также должен помнить имена переменных для каждого контекста, чтобы разрешить eval, поэтому его кадры и вызовы методов медленнее. Кроме того, в настоящее время он не имеет хорошего JIT-компилятора, хотя MRI 1.9 имеет компилятор байт-кода (что лучше), а jruby компилирует его в java-байт-код, который затем (может) компилироваться через компилятор JSM JTM HotSpot, но он заканчивается тем, что с той же скоростью, что и 1.9.

Насколько эффективна производительность сборщика мусора? Я знаю, что у меня были времена, когда запуск сборщика мусора занимал несколько секунд, особенно при работе с библиотеками OpenGL.

из некоторых графиков в http://www.igvita.com/2009/06/13/profiling-ruby-with-googles-perftools/ Я бы сказал, что это занимает около 10%, что совсем немного - вы можете уменьшить которые пострадали от увеличения malloc_limit в gc.c и перекомпиляции.

Я использовал матричные математические библиотеки с Ruby, которые были особенно медленными. Есть ли проблема с тем, как Ruby реализует базовую математику?

Ruby 1.8 "не реализовал базовую математику, в которой реализованы числовые классы, и вы бы назвали такие вещи, как Fixnum # + Fixnum #/один раз за вызов, - который был медленным. Ruby 1.9 немного обманывает, вставляя некоторые основные математические операции.

Существуют ли какие-либо динамические функции в Ruby, которые просто невозможно реализовать эффективно? Если да, то как другие языки, такие как Lua и Python, решают эти проблемы?

Такие вещи, как eval, трудно реализовать эффективно, хотя многое можно сделать, я уверен. Кикер для Ruby заключается в том, что он должен вмещать кого-то в другой поток, меняя определение класса спонтанно, поэтому он должен быть очень консервативным.

Была ли проведена недавняя работа, которая значительно улучшила производительность?

1.9 похож на 2x ускорение. Это также более эффективное пространство. JRuby постоянно пытается улучшить скорость [и, вероятно, тратит меньше времени на GC, чем KRI]. Кроме того, я не знаю многого, кроме маленьких хобби, над которыми я работал. Обратите также внимание на то, что 1.9 строк иногда медленнее из-за удобства кодирования.

Ответ 2

Ruby очень хорош для быстрой доставки решений. Меньше для доставки быстрых решений. Это зависит от того, какую проблему вы пытаетесь решить. Мне вспоминается обсуждение старого форума CompuServe MSBASIC в начале 90-х: когда его спросили, что быстрее для разработки Windows, VB или C, обычный ответ был "VB, примерно на 6 месяцев".

В своей форме MRI 1.8 Ruby - относительно медленный, чтобы выполнять некоторые типы вычислительно-интенсивных задач. Практически любой интерпретируемый язык страдает таким образом по сравнению с большинством скомпилированных языков.

Причины несколько: некоторые довольно легко адресуемые (например, примитивная сборка мусора в 1.8), а тем более менее.

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

Что касается математической производительности, я бы не удивился, увидев довольно медленную пропускную способность: это часть цены, которую вы платите за произвольную точность. Опять же, выберите свою проблему. Я решил 70+ проблем

Ответ 3

Самая проблематичная часть - "все".

Бонусные баллы, если "каждый" на самом деле не использовал язык.

Серьезно, 1.9 намного быстрее и теперь находится на одном уровне с python, а jruby быстрее, чем jython.

Сборщики мусора повсюду; например, Java имеет один, и он быстрее, чем С++ для обработки динамической памяти. Ruby не подходит для хруста; но мало языков, поэтому, если у вас есть вычислительно-интенсивные части в вашей программе на любом языке, лучше переписать их на C (Java быстро с математикой из-за ее примитивных типов, но она дорого заплатила за них, они явно # 1 в самых уродливых частях языка).

Что касается динамических функций: они не быстры, но код без них на статических языках может быть еще медленнее; например, java будет использовать конфигурацию XML вместо Ruby, используя DSL; и это, вероятно, будет SLOWER, поскольку синтаксический анализ XML является дорогостоящим.

Ответ 4

Хммм. Несколько лет назад я работал над проектом, где я скрестил ствол с работой Ruby, и с тех пор я не уверен, что многое изменилось. Прямо сейчас это предостерегает emptor - вы должны знать, что не делать определенные вещи, и откровенно игры/приложения в реальном времени были бы одним из них (поскольку вы упоминаете OpenGL).

Преступником для убийства интерактивной производительности является сборщик мусора - другие здесь упоминают, что Java и другие среды также имеют сборку мусора, но Ruby должен остановить мир для запуска. Иными словами, он должен остановить запуск вашей программы, сканировать через каждый регистр и указатель памяти с нуля, пометить память, которая все еще используется, и освободить остальные. Процесс не может быть прерван, когда это произойдет, и, как вы могли заметить, это может занять сотни миллисекунд.

Его частота и продолжительность выполнения пропорциональны количеству объектов, которые вы создаете и уничтожаете, но если вы вообще не отключите их, вы не сможете управлять им. Мой опыт заключался в нескольких неудовлетворительных стратегиях сглаживания моего цикла анимации Ruby:

  • GC.disable/GC.enable вокруг критических циклов анимации и, возможно, оппортунистического GC.start, чтобы заставить его идти, когда он не может навредить. (потому что моя целевая платформа в то время была 64-мегабайтной машиной Windows NT, это приводило к тому, что в системе иногда не хватало памяти. Но в корне это плохая идея - если вы не можете предварительно вычислить, сколько памяти вам может понадобиться, прежде чем делать это, вы "рисковать исчерпанием памяти".
  • Уменьшите количество создаваемых объектов, чтобы у GC было меньше работы (уменьшает частоту/длину его выполнения)
  • Запишите свой цикл анимации в C (выезд, но тот, с которым я пошел!)

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

Другая важная проблема с производительностью, которую я обнаружил, - это базовый ввод-вывод при попытке написать TFTP-сервер в Ruby некоторое время назад (да, я выбираю все лучшие языки для своих критически важных для производительности проектов, это был просто эксперимент), Абсолютный простейший строгий цикл для простого ответа на один пакет UDP с другим, связанный с следующим фрагментом файла, должен был быть примерно в 20 раз медленнее, чем версия C. Я подозреваю, что, возможно, были некоторые улучшения, связанные с использованием низкоуровневого ввода-вывода (sysread и т.д.), Но медленность может заключаться в том, что нет типа данных байтов низкого уровня - каждое небольшое чтение копируется в Строка. Это только предположение, однако, я не принимал этот проект намного дальше, но он предупредил меня, полагаясь на мгновенный ввод-вывод.

Последнее увеличение скорости, которое продолжалось, хотя я не совсем в курсе последних событий, заключается в том, что реализация виртуальной машины была переделана на 1,9, что привело к более быстрому выполнению кода. Однако Я не думаю, что GC изменился, и я почти уверен, что на фронте ввода-вывода нет ничего нового. Но я не полностью обновляюсь на Ruby-edge Ruby, поэтому кто-то может захотеть здесь поиграть.

Ответ 5

Стив Декорте: "Написание калькулятора Set Mandelbrot на языке высокого уровня похоже на попытку запустить Indy 500 в шине".

http://www.dekorte.com/blog/blog.cgi?do=item&id=4047

Я рекомендую изучить различные инструменты, чтобы использовать правильный инструмент для работы. Выполнение матричных преобразований можно было бы эффективно использовать с использованием высокоуровневого API, который обтекает узкие циклы с вычислениями с интенсивным арифметическим вычислением. См. RubyInline gem для примера встраивания кода C или С++ в Ruby script.

Существует также язык Io, который намного медленнее, чем Ruby, но он эффективно отображает фильмы в Pixar и превосходит исходную C на векторной арифметике с использованием ускорения SIMD.

Ответ 6

Я предполагаю, что вы спрашиваете: "Какие конкретные методы в Ruby имеют тенденцию быть медленными".

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

Ответ 7

Ruby 1.9.1 примерно в два раза быстрее, чем PHP, и немного быстрее, чем Perl, согласно некоторым критериям.

(Обновление: мой источник this (снимок экрана). Я не знаю, каков его источник.)

Ruby не медленный. Старый 1.8 есть, но текущий Ruby не является.

Ответ 8

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

Ответ 9

IMO, динамические языки в целом медленны. Они делают что-то во время выполнения, что статические языки делают во время компиляции.

Проверка синтаксиса, Интерпретация и проверка типа, конвертирование. это неизбежно, поэтому рубин медленнее, чем c/С++/java, исправьте меня, если я ошибаюсь.