我有一个需要显示蒙特卡罗SIM卡结果的Rails应用程序,而且Ruby第一次不够快,无法满足我的需求.所以,我开始四处寻找是否可以在C中重写我的模拟并在Ruby中使用这些结果,并且一些谷歌搜索出现了RubyInline gem,可以直接在Ruby中编写更快的C代码.做一些简单的东西很有用,例如,用Ruby和C编写的一些基本函数:
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)
Run Code Online (Sandbox Code Playgroud)
所以,很棒,它肯定会加速我的SIM卡,因为它几乎只是生成随机数并根据这些结果添加内容.不幸的是,除了这样的基本内容之外,我无法弄清楚如何实际编写我的程序.我需要传递一些结构来充当状态变量,所以业务的第一顺序是弄清楚如何创建一个C结构.阅读文档,似乎应该相当简单.
访问器(方法,类型,成员=方法)
为通过Data_Wrap_Struct包装的C结构成员添加读写器.方法是给出访问者的ruby名称,类型是C类型.除非用成员覆盖C成员名称,否则方法名称将用作结构成员.
Run Code Online (Sandbox Code Playgroud)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'
Run Code Online (Sandbox Code Playgroud)
不幸的是,我甚至无法做到这一点
*/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:3:错误:使用未声明的标识符'MyStruct'MyStruct*指针; ^*/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:13:错误:使用未声明的标识符'指针'MyStruct*指针; ^*/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:458:35:错误:使用未声明的标识符'指针'Data_Get_Struct (self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6:注意:从宏扩展'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:错误:使用未声明的标识符'MyStruct'Data_Get_Struct (self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:15:注意:从宏扩展'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:错误:预期表达式Data_Get_Struct(self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:20:注意:从宏扩展'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:错误:使用未声明的标识符'指针'返回(rb_str_new2(指针- >标题)); ^*/.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/intern.h:786:27:注意:从宏'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:错误:使用未声明的标识符'指针'*/.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/intern.h:787:14:注意:从宏扩展'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:错误:使用未声明的标识符'指针'*/.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/intern.h:787:33:注意:从宏'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:错误:使用未声明的标识符'指针'*/.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/intern.h:788:18:注意:从宏'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:错误:从函数返回'void'与不兼容的结果类型'VALUE'(又名'unsigned long')返回(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:错误:使用未声明的标识符'MyStruct'MyStruct*指针; ^*/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:478:13:错误:使用未声明的标识符'指针'MyStruct*指针; ^*/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:480:35:错误:使用未声明的标识符'指针'Data_Get_Struct (self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6:注意:从宏扩展'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:错误:使用未声明的标识符'MyStruct'Data_Get_Struct (self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:15:注意:从宏扩展'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:错误:预期表达式Data_Get_Struct(self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:20:注意:从宏扩展'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:错误:使用未声明的标识符'指针'指针 - > title = StringValuePtr(value); ^*/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:3:错误:使用未声明的标识符'MyStruct'MyStruct*指针; ^*/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:13:错误:使用未声明的标识符'指针'MyStruct*指针; ^*/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:458:35:错误:使用未声明的标识符'指针'Data_Get_Struct (self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6:注意:从宏扩展'Data_Get_Struct'(sval)=(type)DATA_PTR(obj);\^致命错误:发出太多错误,现在停止[-ferror-limit =]
我已经做了一堆谷歌搜索,但几乎每个我发现的例子只涉及我最初概述的简单用例.吐出的第一个错误是MyStruct未声明,所以我尝试在访问器方法之前添加结构定义,如下所示:
builder.c '
typedef struct
{
char *title;
int index;
} MyStruct;
'
Run Code Online (Sandbox Code Playgroud)
这没有做任何事情,文档似乎很清楚c方法仅用于声明函数,而不是结构.我不确定下一步该尝试什么,其他人是否有这方面的经验?
如果您正在做比基础知识更复杂的事情,RubyInline 似乎假设您知道编写 Ruby 扩展的方法。
\n\n您确实需要像您尝试的那样自己定义结构,但是您应该使用prefix方法而不是c方法(用于定义方法)。您还需要定义类的分配方法。您可以通过添加一个名为 RubyInline 将识别并用作分配函数的函数来使用该方法来完成此c_singleton操作allocate(这似乎没有记录在案,我通过查看源代码找到了它)。
把它们放在一起看起来像这样。
\n\nclass Foo\n inline do |builder|\n\n # First define the struct that will be wrapped in the\n # class.\n builder.prefix <<-DEFINE_STRUCT\n typedef struct {\n char* bar;\n } MyStruct;\n DEFINE_STRUCT\n\n # Next define the allocation function that will\n # allocate and wrap a MyStruct struct when creating a\n # new Foo object. You might want to initialize the values\n # to avoid possible segfaults.\n builder.c_singleton <<-ALLOCATE\n VALUE allocate() {\n MyStruct* pointer = ALLOC(MyStruct);\n return Data_Wrap_Struct(self, NULL, free, pointer);\n }\n ALLOCATE\n\n # Finally we can use the struct_name and accessor methods.\n builder.struct_name = \'MyStruct\'\n builder.accessor \'bar\', \'char *\' \n end\n\nend\nRun Code Online (Sandbox Code Playgroud)\n\n.ruby_inline请注意,如果您查看主目录中的目录,您可以看到生成的 C 代码。