Ruby integrates very easily with the C programming language. You can create extensions for Ruby. Or we can make a wrapper for the C library, and use it as a regular Ruby library. You can also implement critical C calculations right in Ruby code! Another integration option is to use Ruby in C / C ++ programs as a scripting language. For example, as done in Google SketchUp.
Let's see what features Ruby provides for integration with C.
Suppose there is a bottleneck in our program, some sort of calculation that, for example, is performed in a loop. These calculations greatly reduce application performance.
The solution is to rewrite a critical piece in C, since compiled languages are known to be faster interpreted.
')
Here we have two options, either create an extension for Ruby, or use C code directly from Ruby.
To begin with, we will choose the second option, and in this the RubyInline library will come to our aid.
Suppose we have a method for decomposing a number into prime dividers. Let's follow the simplest path and implement this method using the brute force algorithm:
class factor
#num - input number, show - whether to display the result on the screen
def factorization num, show = false
num1 = num
n = 2 # start searching for divisors from 2
while n * n <= num1
if num% n == 0 # if the current number is a divisor, output it
num = num / n
puts n if show
else # otherwise we increase the current number
n + = 1
end
end
end
end
But we are not satisfied with the speed of this method, so let's rewrite it in C, using the RubyInline library.
First, install it:
gem install RubyInline
RubyInline requires a POSIX system, i.e. either * nix or Cygwin on Windows.
And also a C / C ++ compiler.
A simple example of use:
require 'rubygems'
require 'inline' # connect RubyInline
class Test
# embedded code handler
inline do | builder | # an object of class Inline :: C is passed to the block
builder.c '
static char * test () {
return "Hi from C! :)";
}
'
end
end
puts Test.new.test # prints "Hi from C! :)"
In the sample code, we made a small C method that returns a greeting string.
Method
c
performs the following actions:
- performs conversion of argument types and return values from C to Ruby
- compiles a string with the method code
- adds test method to class Test
After that, we can use
test
as a normal Ruby method.
Let's return to factoring. Rewrite the factorization method using RubyInline.
require 'rubygems'
require 'inline'
class FastFactor
inline do | builder |
builder.c '
static void factorization (int num, int show) {
int i = 0;
int num1 = num;
int n = 2;
while (n * n <= num1) {
if (num% n == 0) {
num = num / n;
if (show)
printf ("% d \ n", n);
i ++;
} else {
n ++;
}
}
}
'
end
end
And now, the most interesting. Performance tests
Ruby implementation test:
f = Factor.new
1000.times {f.factorization 999999}
Result:
$ time ruby factor.rb
real 0m1.034s
user 0m1.028s
sys 0m0.004s
And similar to C:
f = FastFactor.new
1000.times {f.factorization 999999, false}
And the result:
time ruby factorfast.rb
real 0m0.116s
user 0m0.092s
sys 0m0.024s
As can be seen from the test, RubyInline allows you to speed up critical pieces of code almost 10 times!
Test code:
factor.rb ,
factorfast.rb .
Summarizing, we can say that if our application cannot cope with the workloads, then we can always speed it up by implementing critical moments in C. Fortunately, Ruby provides us with powerful and convenient means for this.
In the next part, I’ll talk about creating C extensions for Ruby.
Related Links:
RubyInline:
http://rubyforge.org/projects/rubyinline/Documentation:
http://rubyinline.rubyforge.org/RubyInline/