2015-04-18 5 views
5

У меня есть приложение Rails, которое должно показать результаты симулятора Monte Carlo, и в первый раз Ruby просто не достаточно быстро для моих нужд. Итак, я начал копаться, чтобы посмотреть, могу ли я переписать мою симуляцию на C и использовать эти результаты в Ruby, а некоторые googling превратили RubyInline gem, чтобы легко писать более быстрый код C непосредственно в Ruby. Делая простые вещи отлично работает, например, некоторые основные функции написаны на Ruby, и C:Создание C структур с использованием RubyInline gem

class FasterFunctions 
    inline do |builder| 
    builder.c ' 
    double rand_sum(int trials) 
    { 
     double sum = 0.0; 
     for (int i = 0; i<trials; i++) 
     { 
     sum += (double)rand()/(double)RAND_MAX; 
     } 
     return sum; 
    }' 

    builder.c ' 
    long loop_sum(long trials) 
    { 
     long sum = 0; 
     for (long i = 0; i<trials; i++) 
     { 
     sum+=i; 
     } 
     return sum; 
    }' 
    end 
end 

#the C version is 4 orders of magnitude faster 
trials = 1_000_000 
ruby_sum = 0 
trials.times {|i| ruby_sum += i} 
c_sum = FasterRand.new.loop_sum(trials) 

# the C version is 1 order of magnitude faster 
ruby_sum = 0.0 
trials.times {ruby_sum += rand} 
c_sum = FasterRand.new.rand_sum(trials) 

Так, большой, он должен определенно ускорить мой сим, так как это в значительной степени просто генерации случайных чисел и добавление материала на основе по этим результатам. К сожалению, помимо основных вещей, подобных этому, я не могу понять, как писать свою программу. Мне нужно передать некоторые структуры, чтобы действовать как переменные состояния, поэтому в первом порядке бизнеса выясняется, как создать структуру C. Чтение the documentation, похоже, должно быть довольно простым.

accessor(method, type, member = method)

Adds a reader and writer for a C struct member wrapped via Data_Wrap_Struct. method is the ruby name to give the accessor, type is the C type. Unless the C member name is overridden with member, the method name is used as the struct member.

builder.struct_name = 'MyStruct' 
builder.accessor :title,  'char *' 
builder.accessor :stream_index, 'int', :index 

документация не совсем ясно для меня, но я предполагаю, что я положил, что в классе много, как раньше, и сделать что-то вроде следующего, чтобы получить доступ к нему:

class MyStructClass 
    inline do |builder| 
    builder.struct_name = 'MyStruct' 
    builder.accessor :title, 'char *' 
    builder.accessor :stream_index, 'int', :index 
    end 
end 

#possible this 
struct = MyStructClass.new.MyStruct 
struct.title = 'A Title' 

#or maybe 
struct = MyStructClass.new 
struct.title = 'A Title' 

К сожалению , я даже не могу получить, что далеко

*/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:3: error: use of undeclared identifier 'MyStruct' MyStruct *pointer; ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:13: error: use of undeclared identifier 'pointer' MyStruct *pointer; ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:458:35: error: use of undeclared identifier 'pointer' Data_Get_Struct(self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6: note: expanded from macro 'Data_Get_Struct' (sval) = (type)DATA_PTR(obj);\ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:458:25: error: use of undeclared identifier 'MyStruct' Data_Get_Struct(self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:15: note: expanded from macro 'Data_Get_Struct' (sval) = (type)DATA_PTR(obj);\ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:458:3: error: expected expression Data_Get_Struct(self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:20: note: expanded from macro 'Data_Get_Struct' (sval) = (type)DATA_PTR(obj);\ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:460:23: error: use of undeclared identifier 'pointer' return (rb_str_new2(pointer->title)); ^ */.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/intern.h:786:27: note: expanded from macro 'rb_str_new_cstr' (__builtin_constant_p(str)) ? \ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:460:23: error: use of undeclared identifier 'pointer' */.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/intern.h:787:14: note: expanded from macro 'rb_str_new_cstr' rb_str_new((str), (long)strlen(str)) : \ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:460:23: error: use of undeclared identifier 'pointer' */.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/intern.h:787:33: note: expanded from macro 'rb_str_new_cstr' rb_str_new((str), (long)strlen(str)) : \ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:460:23: error: use of undeclared identifier 'pointer' */.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/intern.h:788:18: note: expanded from macro 'rb_str_new_cstr' rb_str_new_cstr(str); \ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:460:10: error: returning 'void' from a function with incompatible result type 'VALUE' (aka 'unsigned long') return (rb_str_new2(pointer->title)); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:478:3: error: use of undeclared identifier 'MyStruct' MyStruct *pointer; ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:478:13: error: use of undeclared identifier 'pointer' MyStruct *pointer; ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:480:35: error: use of undeclared identifier 'pointer' Data_Get_Struct(self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6: note: expanded from macro 'Data_Get_Struct' (sval) = (type)DATA_PTR(obj);\ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:480:25: error: use of undeclared identifier 'MyStruct' Data_Get_Struct(self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:15: note: expanded from macro 'Data_Get_Struct' (sval) = (type)DATA_PTR(obj);\ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:480:3: error: expected expression Data_Get_Struct(self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:20: note: expanded from macro 'Data_Get_Struct' (sval) = (type)DATA_PTR(obj);\ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:482:3: error: use of undeclared identifier 'pointer' pointer->title = StringValuePtr(value); ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:3: error: use of undeclared identifier 'MyStruct' MyStruct *pointer; ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:13: error: use of undeclared identifier 'pointer' MyStruct *pointer; ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:458:35: error: use of undeclared identifier 'pointer' Data_Get_Struct(self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6: note: expanded from macro 'Data_Get_Struct' (sval) = (type)DATA_PTR(obj);\ ^fatal error: too many errors emitted, stopping now [-ferror-limit=]

Я сделал кучу прибегая к помощи, но в значительной степени каждый примере я нашел дело только с простым прецедентом я обрисовал в первом. Первая ошибка это выплюнуть, что MyStruct была необъявленная, поэтому я попытался добавить определение структуры до методов доступа, например, так:

builder.c ' 
    typedef struct 
    { 
    char *title; 
    int index; 
    } MyStruct; 
' 

Это ничего не делать, а документация представляется очевидным, что c метод предназначен только для объявления функций, а не для структур. Я не совсем уверен, что делать дальше, есть ли у кого-нибудь еще опыт?

ответ

3

RubyInline, похоже, полагает, что вы знаете свой путь вокруг написания расширений Ruby, если вы делаете что-либо более сложное, чем основы.

Вы сделать необходимо определить структуры, как вы сами пробовали, но вы должны использовать prefix method, а не c method (что для определения методов). Вам также необходимо определить метод распределения для класса. Вы можете сделать это с помощью c_singleton method, добавив функцию с именем allocate, которую RubyInline будет распознавать и использовать в качестве функции распределения (это, похоже, не документировано, я нашел ее, посмотрев на источник).

Складывать все вместе выглядит примерно так.

class Foo 
    inline do |builder| 

    # First define the struct that will be wrapped in the 
    # class. 
    builder.prefix <<-DEFINE_STRUCT 
     typedef struct { 
     char* bar; 
     } MyStruct; 
    DEFINE_STRUCT 

    # Next define the allocation function that will 
    # allocate and wrap a MyStruct struct when creating a 
    # new Foo object. You might want to initialize the values 
    # to avoid possible segfaults. 
    builder.c_singleton <<-ALLOCATE 
     VALUE allocate() { 
     MyStruct* pointer = ALLOC(MyStruct); 
     return Data_Wrap_Struct(self, NULL, free, pointer); 
     } 
    ALLOCATE 

    # Finally we can use the struct_name and accessor methods. 
    builder.struct_name = 'MyStruct' 
    builder.accessor 'bar', 'char *' 
    end 

end 

Примечание вы можете увидеть сгенерированный код C, если вы смотрите в каталоге .ruby_inline в вашем домашнем каталоге.

Смежные вопросы