Ruby is a dynamic, reflective, object-oriented, general-purpose programming language. Ruby was influenced by Perl, Smalltalk, Eiffel, Ada, and Lisp. It supports multiple programming paradigms, including functional, object-oriented, and imperative.

As a scripting language, Ruby runs with an Interpreter. The official Ruby interpreter often referred to as the Matz’s Ruby Interpreter or MRI. This implementation is written in C and uses its own Ruby-specific virtual machine.

Many people claim that Ruby does not have the same performance compared to other languages. While this may be more or less true, we have to consider that much of the performance you get will depend on many factors, including the interpreter we are using.

JRuby

Besides the MRI, another of the interpreters available that supports the Ruby programming language is JRuby.

According to the official documentation, JRuby is a 100% Java implementation of the Ruby programming language. It is Ruby for the JVM.

JRuby is Ruby 2.2 compatible and supports Rails 4.

Disadvantage from JRuby:

JRuby cannot run native C extensions, however, but popular libraries have all generally been ported to Java Native Extensions. So, in general, we will find an alternative library for JRuby.

Which is faster: MRI Ruby or JRuby?

This depends, but we can can make do some benchmarking to try to answer

Example 1 with 5000 iterations:

# benchmark.rb
require 'benchmark'

n = 5000
Benchmark.bm do |x|
  x.report { for i in 1..n; a = "1"; end }
  x.report { n.times do   ; a = "1"; end }
  x.report { 1.upto(n) do ; a = "1"; end }
end

1a) Benchmark results with Ruby MRI 2.2.1p85:

$ ruby benchmark.rb
       user     system      total        real
   0.000000   0.000000   0.000000 (  0.000701)
   0.000000   0.000000   0.000000 (  0.000664)
   0.000000   0.000000   0.000000 (  0.000619)

1b) Benchmark results with JRuby 1.7.19 (1.9.3p551):

$ ruby benchmark.rb
       user     system      total        real
   0.010000   0.000000   0.010000 (  0.017000)
   0.020000   0.000000   0.020000 (  0.012000)
   0.020000   0.000000   0.020000 (  0.008000)

We can see in the output, that in this case, Ruby MRI is more faster than the JRuby JVM.

But, what happen with a high load of data, e.g. with 50000000 iterations rather than 5000?

Example 2 with 50000000 iterations:

#benchmark.rb
require 'benchmark'

n = 50000000
Benchmark.bm do |x|
  x.report { for i in 1..n; a = "1"; end }
  x.report { n.times do   ; a = "1"; end }
  x.report { 1.upto(n) do ; a = "1"; end }
end

2a) Benchmark results with Ruby MRI 2.2.1p85:

$ ruby benchmark.rb
       user     system      total        real
   6.500000   0.010000   6.510000 (  6.517888)
   5.910000   0.010000   5.920000 (  5.915001)
   6.290000   0.010000   6.300000 (  6.298892)

2b) Benchmark results with JRuby 1.7.19 (1.9.3p551):

$ ruby benchmark.rb
       user     system      total        real
   3.750000   0.130000   3.880000 (  3.450000)
   2.440000   0.060000   2.500000 (  2.310000)
   2.640000   0.110000   2.750000 (  2.471000)

In the second example, we can see that the time is greatly reduced with JRuby and JVM.

Not bad, but what happens if we change our example with 3 Threads?

Example 3 with independent threads and joins:

#benchmark.rb
require 'benchmark'

n = 50000000
Benchmark.bm do |x|
  t1 = Thread.new { x.report {for i in 1..n; a = "1"; end } }
  t2 = Thread.new { x.report {n.times do   ; a = "1"; end } }
  t3 = Thread.new { x.report {1.upto(n) do ; a = "1"; end } }
  t1.join # wait for thread 1 to finish
  t2.join # wait for thread 2 to finish
  t3.join # wait for thread 3 to finish
end

3a) Benchmark results with Ruby MRI 2.2.1p85:

$ ruby benchmark.rb
       user     system      total        real
 14.820000   0.020000  14.840000 ( 14.825962)
 14.970000   0.020000  14.990000 ( 14.982919)
 14.880000   0.020000  14.900000 ( 14.890429)

3b) Benchmark results with JRuby 1.7.19 (1.9.3p551):

$ ruby benchmark.rb
       user     system      total        real
  5.810000   0.130000   5.940000 (  2.164000)
 12.580000   0.290000  12.870000 (  5.549000)
 13.320000   0.320000  13.640000 (  6.227000)

Now we are able to see a big difference in the real time and total time. JRuby in this case is much faster.

Why is JRuby an improvement when compared with MRI?

The key is the number of concurrent threads running simultaneously.

MRI can have multiple threads, but run only one at a time, while JRuby, through the JVM can run several simultaneously, making it a more intense use of processing, allowing multiple runs, each on a separate CPU thread if we have the hardware for support it and if our application is thread safe.

We can verify using the top command:

MRI:

PID    COMMAND      %CPU  TIME     #TH    #WQ  #PORT MEM
11249  ruby         99.6  00:08.83 5/1    0    16    5188K

JRuby:

PID   COMMAND      %CPU   TIME     #TH   #WQ  #PORT  MEM
11258  java         267.6 00:09.13 31/3   3    237   98M

Where TH: Number of threads (total/running).

Conclusion

Each interpreter is best suited for a particular situation, but in case we need high processing power, besides reviewing the order of complexity of an algorithm, we can also try JRuby as an alternative to see if it improves the actual processing time of our application or API.

###References & more information:

Ruby Official Site

Ruby Programming Language

MRI

JRuby Official Site

JRuby Wiki

Differences between MRI and JRuby

Multithreading ruby

Thread safety for your Rails