Если вы выполняете вычисления на Integer
с, а Integer
s вписываются в native_word_size - 1 бит, тогда YARV будет использовать собственную машинную арифметику на Fixnum
с. Если вы выполняете вычисления на Float
с, работаете на 64-битной платформе и ваши вычисления укладываются в 62-битные вычисления, YARV будет использовать собственную арифметику FPU для flonums . В любом случае, это не намного быстрее, чем , если ваши операции не будут настолько тривиальными, что JIT JVM (или компилятор JRuby) может полностью их оптимизировать, постоянно сворачивать их или что-то подобное.
Лучшее место - Integer
s, которые больше 63 бит, но меньше 64 бит, которые обрабатываются JRuby как целые числа машин, но не YARV, то же самое для Float
s больше 62, но меньше 64 биты. В этом диапазоне JRuby будет использовать собственные операции, а YARV - нет, что дает JRuby преимущество в производительности.
В целом, YARV превосходит JRuby по задержке , особенно по времени запуска. Однако это во многом зависит от используемой JVM и среды. Существуют JVM, которые предназначены для очень быстрого запуска (например, IBM J9, для которой IMO должна быть настольной JVM по умолчанию вместо Oracle HotSpot) или Avian (которая на самом деле не является JVM, поскольку она реализует только подмножество JVM и JRE спецификации, но, тем не менее, может запускать многие нетривиальные программы, которые не используют ни одну из не реализованных функций, в том числе JRuby.) Кроме того, существуют среды и конфигурации, которые позволяют вам сохранять и повторно использовать JVM и экземпляр JRuby в памяти, исключающий значительную часть времени запуска.
Вторая важная вещь - это расширения YARV C. YARV имеет очень открытый и широкий API для расширений Си. По сути, расширения YARV C могут получить доступ практически ко всем частным внутренним деталям реализации YARV. (Это, очевидно, означает, что они могут повредить и привести к сбою YARV.) С другой стороны, «расширения C» JVM всегда должны проходить через барьер безопасности. Они могут испортить только память, явно переданную им Java-кодом, который их вызывает, они никогда не повредят другую память, не говоря уже о самой JVM. Однако это связано с затратами на производительность: вызов C из Java или наоборот * на 1021 * обычно медленнее, чем вызов C из YARV и наоборот.
Расширения YARV C на даже медленнее , чем это, поскольку JRuby, по сути, должен предоставить целый слой сложной эмуляции, эмулирующий внутренние структуры данных, функции и макет памяти YARV, чтобы получить хотя бы некоторые Расширения YARV C для запуска. Это просто медленно. Период.
Обратите внимание, что это не относится к оболочкам Ruby для библиотек C, которые используют Ruby FFI API. Они не зависят от внутренних компонентов YARV и, следовательно, не нуждаются в уровне эмуляции, а в JRuby реализована довольно быстрая и оптимизированная реализация Ruby FFI API. Стоимость мостового соединения JVM ↔ C по-прежнему применяется, однако.
Это две большие вещи, где YARV работает быстрее: код, который выполняется слишком коротко, чтобы воспользоваться преимуществами оптимизации JVM для долго выполняющихся процессов, и код, который интенсивно использует вызовы в и из C, особенно Расширения YARV C.
Если вы можете заставить свой код работать на TruffleRuby, это был бы интересный эксперимент. Оптимизация, которую может выполнять TruffleRuby, действительно удивительна (например, сворачивание всей библиотеки Ruby с использованием значительного количества динамического метапрограммирования, отражения и Hash
поисков в одну константу), и она может приближаться и даже превосходить оптимизированный вручную C. Кроме того, TruffleRuby содержит интерпретатор C в дополнение к интерпретатору Ruby, и, таким образом, может анализировать и оптимизировать код Ruby, обращающийся к расширениям C и наоборот, и даже выполнять межязыковое встраивание, что означает, что в некоторых тестах он может выполнять код Ruby, интенсивно используя Расширения YARV быстрее чем YARV!