The relationship between ruby ​​script and running C ++ program

I have a C ++ program that performs one function. It loads a large array of data into an array, receives an array of integers and searches in that array, returning a single integer. I am currently invoking a program with each integer as an argument, for example:

$ ./myprogram 1 2 3 4 5 6 7 

I also have a ruby ​​script, and I would like this script to use a C ++ program. I am currently doing it like this.

Ruby Code:

 arguments = "1 2 3 4 5 6 7" an_integer = %x{ ./myprogram #{arguemnts} } puts "The program returned #{an_integer}" #=> The program returned 2283 

This works fine, but my problem is that every time ruby ​​makes this call, the C ++ program has to reload the data file (which exceeds 100 MB) - very slow and very inefficient.

How can I rewrite my program in C ++ by uploading the file only once, which allows me to do many searches with ruby ​​script without reloading the file every time. Would using sockets be a smart approach? Writing a C ++ program as a ruby ​​extension?

Obviously, I'm not an experienced C ++ programmer, so thanks for your help.

+4
source share
2 answers

A possible approach is to change your C ++ program so that it contributes its input from the standard input stream (std :: cin) instead of command line parameters and returns its result through standard output (std :: cout) instead of the main return value. Your Ruby script will then use popen to run the C ++ program.

Assuming the C ++ program looks like this:

 // *pseudo* code int main(int argc, char* argv[]) { large_data_file = expensive_operation(); std::vector<int> input = as_ints(argc, argv); int result = make_the_computation(large_data_file, input); return result; } 

It will be converted to something like:

 // *pseudo* code int main(int argc, char* argv[]) { large_data_file = expensive_operation(); std::string input_line; // Read a line from standard input while(std:::getline(std::cin, input_line)){ std::vector<int> input = tokenize_as_ints(input_line); int result = make_the_computation(large_data_file, input); //Write result on standard output std::cout << result << std::endl; } return 0; } 

And the Ruby script will look like

 io = IO.popen("./myprogram", "rw") while i_have_stuff_to_compute arguments = get_arguments() # Write arguments on the program input stream IO.puts(arguments) # Read reply from the program output stream result = IO.readline().to_i(); end io.close() 
+6
source

Well,

You can do this in several ways.

1) A simple, potentially ugly way to do this is to run your C ++ and periodically check the file so that your ruby ​​script creates a file containing your arguments. Then your C ++ program will use the arguments it contains to return the result to the result file, which you might expect in a ruby ​​script ... This is obviously HACK TASTIC, but it is simple to implement and will work.

2) Suggest your C ++ code as a c extension for ruby. It's not as complicated as it sounds, especially if you use RICE and provide much lower resolution hacks.

3) If your C ++ can be opened through the header file c, then it is almost trivial to build a bridge using FFI. Jeremy Hingardner gave a good lecture on building FFI interfaces in rubyconf heres screencast

4) D-Bus provides the application communication bus, you can change your application to C ++ to use this event bus and send messages from your ruby ​​using ruby-dbus

There are, of course, a thousand other routes ... Maybe one or the other of them may be viable :)

Hurrah!

+3
source

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


All Articles