如何编译Ruby?

发布于 2024-11-05 04:53:06 字数 96 浏览 2 评论 0原文

有没有一个工具可以让我编译 Ruby 代码,使其运行得更快一些?

例如,我听说Python有一个名为“pyc”的工具,可以让我们编译代码,使其运行速度提高10倍。

Is there a tool that can allow me to compile Ruby code so that it runs somewhat faster?

For example, I have heard that there is a tool for Python called "pyc" that allows us to compile the code, so that it runs 10 times faster.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

毁梦 2024-11-12 04:53:06

简单的答案是你不能,至少对于 MRI 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 中,我相信,您可以通过 jrubyc 使用“提前”编译器。

这并不是真正的标准处理方式,通常最好让 Ruby 实现按照自己的意愿处理它。 Rubinius 至少会在第一次编译后缓存字节代码,并根据需要进行更新。

The simple answer is that you can't, at least with MRI 1.8 (the standard). This is because 1.8 works by walking the Abstract Syntax Tree. Python, Ruby 1.9, JRuby, and Rubinius use byte code, which allows compilation to an Intermediate Representation (byte code). From MRI Ruby 2.3 it has become easy to do this, see this answer below.

With Rubinius, you can do something as described in this post: http://rubini.us/2011/03/17/running-ruby-with-no-ruby/

In JRuby you can use the "Ahead Of Time" compiler through, I believe, jrubyc.

This isn't really the standard way of doing things and you're generally better off just letting your Ruby implementation handle it like it wants to. Rubinius, at least, will cache byte code after the first compilation, updating it as it needs to.

咆哮 2024-11-12 04:53:06

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.binread('/home/john/bytecode')
instruction_from_byte_code = RubyVM::InstructionSequence.load_from_binary bytecode

instruction_from_byte_code.eval
# => :shiva

注意:此答案仅在 MRI 中进行测试。它可能在其他 Ruby 实现中起作用,也可能不起作用

From ruby 2.3.0 its so easy to compile your source code to bytecodes that the Ruby-VM understands.

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

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

and in Command Line

$ 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

The content of the file

class A
  def shiva
    puts 'hello'
  end
end

What is the purpose?

Well, ruby takes time to compile your source code into byte codes so you can load your bytecodes directly into ruby and execute. No overhead of grammar checking and compilation. It much faster than normal processes.

How to load byte code?

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

instruction_from_byte_code.eval
# => :shiva

Note: This answer is tested in MRI only. It might or might not work in other Ruby Implementations

泼猴你往哪里跑 2024-11-12 04:53:06

我知道这是一个老问题,但我发现了一个非常有趣的项目,可以为您的问题提供答案:http://crystal -lang.org/

它基本上将 Ruby 编译为本机机器代码。这并不完全正确,因为 Crystal 并不完全是 Ruby,您可能需要对代码进行一些修改。还有一些库(尚未)不受支持,但对我来说,这一切看起来都非常有前途。

I know this is an old question but I found a very interesting project that may provide an answer to your question: http://crystal-lang.org/

It basically compiles Ruby to native machine code. That's not exactly true because Crystal is not exactly Ruby and you might have to make some modifications to your code. There are also libraries that are not supported (yet) but to me it all looks very promising.

故人如初 2024-11-12 04:53:06

2013年初还没有办法将Ruby翻译成C/C++源代码然后编译。

不过,我听Matz(松本幸弘)说,日本的一位研究人员正在创造这个工具。该项目应由日本政府设立。

否则,您可以使用 JRuby 并将其编译为 Java 字节码,或者可以使用 Rubinius。 Rubinius 自动为 Rubinius VM 编译字节码(JIT 编译器)。可以将字节码中的 Rubinius 转换为 LLVM IR,并且 LLVM 可以生成机器代码。

In the beginning of 2013 there is not a way to translate Ruby into C/C++ source and then compile it.

However, I heard Matz (Yukihiro Matsumoto) say that a researcher is creating this tool in Japan. The project should be founded by the Japanese government.

Otherwise you could use JRuby and compile it in Java byte-code or you could use Rubinius. Rubinius compiles automatically in byte-code (JIT compiler) for the Rubinius VM. It is possible to convert Rubinius in byte-code into LLVM IR and LLVM can generate machine code.

浅语花开 2024-11-12 04:53:06

检查 Unholy git 存储库

Check the Unholy git repo

停顿的约定 2024-11-12 04:53:06

以下“独立”Ruby 测试用例基于该线程中的示例,来自名为 magicist 的用户的评论/答案。

#!/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

#==========================================================================

The following "selfcontained" ruby test-case is based on the examples from this very thread, from the comment/answer of the user named 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

#==========================================================================
青衫儰鉨ミ守葔 2024-11-12 04:53:06

尝试使用 ruby-packer 从 Ruby 和 Ruby on Rails 应用程序创建可执行文件

Try ruby-packer which creates executables from Ruby and Ruby on Rails applications

轻许诺言 2024-11-12 04:53:06

我假设您正在运行 CRuby。

您可以在运行 Ruby 时尝试使用 --jit 标志,看看是否能提高速度。否则,我认为您还不能将 Ruby 脚本编译为本机代码。仅通过 RubyVM 模块进行字节码,但我认为您不会从中获得任何好处。

Crystal-lang 或 GraalVM 可以作为您的替代方案(进行一些可能的更改)以获得更高的性能。

I am assuming you're running CRuby.

You could experiment with the --jit flag when running Ruby to see if you gain any speed. Otherwise, I don't think you can compile Ruby scripts into native code yet. Only to bytecode via the RubyVM module but I don't think you'll gain anything from doing it.

Crystal-lang or GraalVM could be your alternative (with some possible changes) for higher performance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文