I am passionate about ruby, but its execution time compared to other languages is extremely high, especially when we want to use algorithms of greater complexity. In general, data structures in interpreted languages become incredibly slow compared to compiled languages. Some algorithms such as ´n-body´ and ´fannkuch-redux´ can be up to 30 times slower in ruby (Ruby vs Go - Benchmark Game)[https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=yarv&lang2=go]. This is one of the reasons I was interested in use embedded GoLang code in a ruby environment.
For those who do not know the operation of the shared libraries, they work in a similar way as the dll files in windows, however it is a native code with a direct interface to the C compiler.
Note:
- Windows uses the DLL system, and in this case, this does not necessarily have to be in native code. One example is DLLs with C #, which runs on a virtual machine. Because I do not use windows, I ended up not testing if it is possible to perform these steps on this operating system.
- You need GoLang 1.5 or higher and ruby 1.8.7 or higher.
It would be like any library, but it must have some peculiar characteristics.
For signing external functions to your library, you will need to use the C language typing. For the rest of the code you can convert to the standard GoLang typing.
To do this include library:
import "C"Remember that this is the Achilles' heel of Go Lang.
Try to generate a small interface, where only a few data is carried here. In general, string translation is extremely slow.
You need to tell the golang compiler which functions will be public in the library. For this you should create a comment above your function.
import "C"
//export MyAdd
func my_add(a, b C.int) C.int {
return a + b
}
func main() {
// This is necessary for the compiler.
// You can add something that will be executed when engaging your library to the interpreter.
}Remember that the exported functions must be in your main package.
Note: I know that the standard of nomenclatures in Golang are different from what we found in this example, but I've created the habit of writing interfaces with the same ruby pattern. For this reason the names of the functions are written with snake_case and not in camelCase.
Just type:
go build -o my_lib.so -buildmode=c-shared my_file.goThis is the fastest way to embed Golang into Ruby environment, however, we remember that in this way the call time of the go interface will not be so fast.
You need to be in an environment **ix. That is, linux or MacOS. We will need these two systems because the gem
we will use only guarantees its operation in these two environments.
Add to your gemfile the following line:
gem 'ffi'Or of course, install manually: gem install ffi
Just create a module and write your function signatures inside the ruby package.
This will act as your library .h file.
require 'ffi'
module Foo
extend FFI::Library
ffi_lib './my_lib.so'
attach_function :my_add, [:int, :int], :int
end
puts Foo.my_add(2, 2)
# => 4How to integrate Golang and Ruby is fast (in time to integrate) and efficient for certain situations. Running the native code in GoLang brings several advantages, bringing you various graphical, database and efficient data structures libraries already implemented in GoLang and the efficiency of Go rotinies. Remember that this applies when we use little data transition between Ruby and GoLang. This will only be advantageous if you have a huge real gain like the algorithms I quoted at the beginning of the post, offsetting this loss by calling a function through the FFI interface.
If it is an algorithm that has little time gain, we recommend using the same strategy, but with pure C or C ++.
If this is a case where the execution gain is a few seconds, you will surely lose performance.