📜 ⬆️ ⬇️

Ruby and C. Part 1.

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/

Source: https://habr.com/ru/post/48928/


All Articles