Как скомпилировать Ruby? - PullRequest
28 голосов
/ 05 мая 2011

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

Например, я слышал, что для Python существует инструмент под названием "pyc", который позволяет нам скомпилировать код, чтобы он работал в 10 раз быстрее.

Ответы [ 6 ]

25 голосов
/ 05 мая 2011

Простой ответ: вы не можете, по крайней мере, с помощью МРТ 1.8 (стандарт).Это потому, что 1.8 работает, обходя абстрактное синтаксическое дерево.Python, Ruby 1.9, JRuby и Rubinius используют байт-код, который позволяет компилировать в промежуточное представление (байт-код).В MRI Ruby 2.3 это стало легко сделать, см. ответ ниже.

С Rubinius вы можете сделать что-то, как описано в этом посте: http://rubini.us/2011/03/17/running-ruby-with-no-ruby/

В JRuby вы можете использовать компилятор "Ahead Of Time" через, я полагаю, jrubyc.

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

6 голосов
/ 22 февраля 2013

В начале 2013 года не было способа перевести Ruby в исходный код C / C ++ и затем скомпилировать его.

Однако я слышал, как Мац (Юкихиро Мацумото) сказал, что исследователь создает этот инструмент в Японии. Проект должен быть основан правительством Японии.

В противном случае вы можете использовать JRuby и скомпилировать его в байт-код Java или использовать Rubinius. Rubinius автоматически компилируется в байт-код (JIT-компилятор) для виртуальной машины Rubinius. Возможно преобразовать Rubinius в байт-коде в LLVM IR, и LLVM может генерировать машинный код.

4 голосов
/ 18 июня 2017

С ruby 2.3.0 настолько легко скомпилировать ваш исходный код в байт-коды, что Ruby-VM понимает.

byte_code = RubyVM::InstructionSequence.compile_file '/home/john/somefile.rb'

File.binwrite '/home/john/bytecode', byte_code.to_binary

и в командной строке

$ cat bytecode 

YARB�
IUsx86_64-linux*.*1

+1�!AA*1
!qy��������yyQ� E/home/john/somefile.rbE<main>E <class:A>EshivaEhelloEAEputsEcore#define_methodu����� 5M

Содержание файла

class A
  def shiva
    puts 'hello'
  end
end

Какова цель?

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

Как загрузить байт-код?

bytecode = File.readbin('/home/john/bytecode')
instruction_from_byte_code = RubyVM::InstructionSequence.load_from_binary byte_code

instruction_from_byte_code.eval
# => :shiva

Примечание : Этот ответ проверен только в MRI . Может работать или не работать в других реализациях Ruby

4 голосов
/ 05 мая 2011

Проверьте Нечестивый GIT РЕПО

3 голосов
/ 07 ноября 2015

Я знаю, что это старый вопрос, но я нашел очень интересный проект, который может дать ответ на ваш вопрос: http://crystal -lang.org /

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

0 голосов
/ 09 декабря 2018

Следующий «самодостаточный» тестовый пример ruby ​​основан на примерах из этой темы, из комментария / ответа пользователя по имени illusionist.

#!/usr/bin/env ruby
#==========================================================================
# This file is in public domain.
# The code of this file is based on the code fragments at the
# 2018_12_09 version of the:
#
#     /4184792/kak-skompilirovat-ruby
#
# This file has been tested with the ruby version
#
#     ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
#
#-----start--of--the--boilerplate------------------------------------------

s_fp_home=ENV["HOME"].to_s
s_fp_tmp=s_fp_home+"/tmp" # using /tmp can be a security risk
s_fp_demofolder=s_fp_tmp+"/ruby_bytecode_usage_demo_01"

def create_folder_if_needed(s_fp_in)
   if !Dir.exists? s_fp_in
      Dir.mkdir(s_fp_in)
      if !Dir.exists? s_fp_in
         raise(Exception.new("\n\n Folder creation failed.\n"+
         "GUID=='d6e409cb-e072-4441-9421-22630190c2e7'\n"))
      end # if
   end # if
end # create_folder_if_needed
create_folder_if_needed(s_fp_tmp)
create_folder_if_needed(s_fp_demofolder)

s_rand=""
7.times{s_rand<<("_"+rand(100).to_s)}

s_fp_bytecode=s_fp_demofolder+"/awesome_bytecode"+s_rand
s_fp_src=s_fp_demofolder+"/x"+s_rand+".rb"

if File.exists? s_fp_src
   raise(Exception.new("\n\n This file should not exist yet.\n"+
   " s_fp_src=="+s_fp_src+"\n"+
   "GUID=='43ab3d45-1324-47af-9441-22630190c2e7'\n"))
end # if
IO.write(s_fp_src,"puts('');puts('Greetings from bytecode!');puts('')")
if !File.exists? s_fp_src
   raise(Exception.new("\n\n The file \n"+s_fp_src+"\n is missing.\n"+
   "GUID=='4aeb5e54-efe0-4111-a851-22630190c2e7'\n"))
end # if


#-----start--of--the--core--of--the--demo----------------------------------

bytecode_out = RubyVM::InstructionSequence.compile_file(s_fp_src)
IO.binwrite(s_fp_bytecode, bytecode_out.to_binary)

bytecode_in = IO.binread(s_fp_bytecode)
instruction_from_byte_code = RubyVM::InstructionSequence.load_from_binary(bytecode_in)
instruction_from_byte_code.eval

#==========================================================================
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...