NOTE: This is a repost of an older blog post of mine from another Blog
I will address one of the primary uses for a C extension in Ruby, speed. Due to it’s very nature, Ruby is slow (as compared to compiled languages like C). It gets the job done, but sometimes it takes it’s sweet time doing it. Sometimes it is necessary to speed things up a bit, and here enter C extensions. There are several methods of implementing extensions, from the generic C extension, to ruby-inline. In this particular article I will focus on the generic C extension.
In this example, I am going to use a fairly inefficient piece of Ruby code I created a while ago for Project Euler (Problem 10) for finding the sum of all primes under 2000000:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
i on line 7 from
3, as otherwise it will cause
5 to return
At the time that I wrote this, I was relatively unaware of more efficient ways of resolving prime numbers (such as a euler sieve), however the code still ran under the allotted 2 minute window (52 seconds) so I went with it. Now to speed it up. To write a C extension you need, at a bare minimum two things:
an extconf.rb file – this file is used by ruby to generate the Makefile that is used to compile the extension the source file for the extension (in this case primed.c) Here is a look at these two files for my new version of problem 10:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
1 2 3 4 5 6 7 8 9 10 11
First let me explain primed.c. The objective of this extension is to determine whether or not a number is prime, so that an integer can call
x.prime? and return
false. It is essentially identical to the method used in the pure ruby script above. One of the first thing you may notice is this line:
VALUE is a data type defined by Ruby that represents the Ruby object in memory. It is basically a struct that contains the data related to the object. In this case, the object will represent the
Primed module in ruby, so it will contain data about the instance methods, variables, etc. for that module. All Ruby objects are represented in C by
VALUE, regardless of their type within the Ruby VM, anything else will likely result in a segfault.
Next we define the actual method to calculate whether the value is prime. Note that because we need to return a Ruby object, we set the return type as
VALUE as well.
QFalse are directly representative of true and false in Ruby, and also return correctly within C (
QTrue will evaluate as
QFalse will evaluate as
Finally we see the
Init_primed method. Every time a class or module is instantiated within the Ruby VM it calles
Init_name. It is here we actually instantiate the
Primed module and bind the
method_prime function to the Ruby method
prime?. Both functions used are pretty self explanatory as to what they do, except for the last argument used in
ruby_define_method which is essentially the arity or number of arguments to expect in the Ruby method. In this case,
-2 actually causes Ruby to send back
self as the first argument to the
method_prime function, and an array of any other arguments as the second.
Now we have all of our code. The last thing to put in place is extconf.rb:
1 2 3 4 5 6 7 8 9 10 11
Pretty simple right? Now when you call ruby extconf.rb it will generate a Makefile that you can use to build the extension. And the final result? Using the C extension the code runs in just under 3 seconds. Still not really efficient, but it demonstrates the point. When Ruby’s speed is the bottle neck, using C is a viable and easy option.