是否有一个工具可以让我编译Ruby代码,以便它运行得更快?
例如,我听说有一个名为“pyc”的Python工具允许我们编译代码,因此运行速度提高了10倍。
答案 0 :(得分:25)
简单的答案是你不能,至少用MRI 1.8(标准)。这是因为1.8通过遍历抽象语法树来工作。 Python,Ruby 1.9,JRuby和Rubinius使用字节代码,允许编译为中间表示(字节代码)。从MRI Ruby 2.3开始,这很容易实现,请参见下面的answer。
使用Rubinius,您可以执行此帖中所述的操作:http://rubini.us/2011/03/17/running-ruby-with-no-ruby/
在JRuby中,你可以使用“Ahead Of Time”编译器,我相信,jrubyc。
这实际上并不是标准的处理方式,而且通常只需让Ruby实现按照自己的意愿处理它就会更好。 Rubinius至少会在第一次编译后缓存字节代码,并根据需要进行更新。
答案 1 :(得分:6)
在2013年初,没有办法将Ruby转换为C / C ++源代码然后进行编译。
然而,我听说Matz(Yukihiro Matsumoto)说研究人员正在日本创造这个工具。该项目应由日本政府建立。
否则你可以使用JRuby并用Java字节码编译它,或者你可以使用Rubinius。 Rubinius在Rubinius VM的字节码(JIT编译器)中自动编译。可以将Rubinius的字节码转换为LLVM IR,LLVM可以生成机器码。
答案 2 :(得分:4)
检查Unholy git repo
答案 3 :(得分:4)
从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 :(得分:3)
我知道这是一个老问题,但我发现了一个非常有趣的项目,可以为您的问题提供答案:http://crystal-lang.org/
它基本上将Ruby编译为本机机器代码。这并不完全正确,因为Crystal并不完全是Ruby,您可能需要对代码进行一些修改。还有一些图书馆不受支持(但是)对我来说这看起来很有希望。
答案 5 :(得分:0)
以下“自包含”红宝石测试用例基于该线程中的示例,来自名为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:
#
# https://stackoverflow.com/questions/5902334/how-to-compile-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
#==========================================================================
答案 6 :(得分:0)
尝试ruby-packer,它可以从Ruby和Ruby on Rails应用程序创建可执行文件