Ruby and C. Part 1.

    Ruby integrates very easily with the C programming language. You can create extensions for Ruby. Or we can do a wrapper for a C library, and use it like a regular Ruby library. You can also implement critical computing in C directly in Ruby code! Another integration option is to use Ruby in C / C ++ programs as a scripting language. For example, how it is done in Google SketchUp.

    Let's see what features Ruby presents for integration with C.


    Let there be a bottleneck in our program, some piece of computation that, for example, runs in a loop. These calculations greatly reduce the performance of the application.
    The solution is to rewrite the critical piece to C, because compiled languages ​​are obviously faster than interpreted ones.

    Here we have two options: either create an extension for Ruby, or use the C code directly from Ruby.
    To begin with, we will choose the second option, and the RubyInline library will come to our aid in this.
    Suppose we have a method for decomposing a number into prime divisors. Let's go along the simplest way, and implement this method with an iterative 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 the search for divisors from two
                while n * n <= num1
                    if num% n == 0 # if the current number is a divisor, print it
                        num = num / n 
                        puts n if show
                    else # otherwise increase the current number
                        n + = 1
                    end
                end
            end
        end

    But we are not happy with the speed of this method, so we will 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.
    As well as the C / C ++ compiler.

    A simple use case:
        require 'rubygems'
        require 'inline' # connect RubyInline
        class test
            # embedded code handler
            inline do | builder | # an Inline :: C class object 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 hello string.
    The method cperforms the following actions:
    - performs conversion of argument types and return value from C to Ruby
    - compiles a string with the method code
    - adds the test method to the Test class.
    After that, we can use it testas a regular Ruby method.

    Let's get back to factorization. Rewrite the factorization method with 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 test implementation:
        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 you can see from the test, RubyInline allows you to accelerate critical pieces of code by almost 10 times!
    Test code: factor.rb , factorfast.rb .
    Summing up, we can say that if our application does not cope with the load, then we can always speed it up by implementing critical points in C. Fortunately, Ruby provides us with powerful and convenient tools for this.

    In the next part I will talk about creating C extensions for Ruby.

    Related links:
    RubyInline: http://rubyforge.org/projects/rubyinline/
    Documentation: http://rubyinline.rubyforge.org/RubyInline/

    Also popular now: