どのように効率的にRubyのC APIで2つのハッシュをマージするには?
-
12-09-2019 - |
質問
私は実際には2つのハッシュをマージする必要がRuby用のC拡張を書いています、しかしrb_hash_merge()関数は、Ruby 1.8.6でSTATICです。私が使用する代わりにしようとしています:
rb_funcall(hash1, rb_intern("merge"), 1, hash2);
が、これは非常に遅すぎる、とパフォーマンスは、このアプリケーションでは非常に重要です。
誰もが心の中で、効率とスピードで、このマージを実行して行く方法を知っていますか?
(注意私は単にrb_hash_mergeのソース(見て)、それを複製しようとしているが、それは解きほぐすことはほぼ不可能と思われるように、さらに多くの静的関数だらけそのものいる他の静的機能、だらけです...私は必要別の方法)
解決
[OK]を、公表API内で最適化することができないかもしれないように見えます。
テストコード:
#extconf.rb
require 'mkmf'
dir_config("hello")
create_makefile("hello")
// hello.c
#include "ruby.h"
static VALUE rb_mHello;
static VALUE rb_cMyCalc;
static void calc_mark(void *f) { }
static void calc_free(void *f) { }
static VALUE calc_alloc(VALUE klass) { return Data_Wrap_Struct(klass, calc_mark, calc_free, NULL); }
static VALUE calc_init(VALUE obj) { return Qnil; }
static VALUE calc_merge(VALUE obj, VALUE h1, VALUE h2) {
return rb_funcall(h1, rb_intern("merge"), 1, h2);
}
static VALUE
calc_merge2(VALUE obj, VALUE h1, VALUE h2)
{
VALUE h3 = rb_hash_new();
VALUE keys;
VALUE akey;
keys = rb_funcall(h1, rb_intern("keys"), 0);
while (akey = rb_each(keys)) {
rb_hash_aset(h3, akey, rb_hash_aref(h1, akey));
}
keys = rb_funcall(h2, rb_intern("keys"), 0);
while (akey = rb_each(keys)) {
rb_hash_aset(h3, akey, rb_hash_aref(h2, akey));
}
return h3;
}
static VALUE
calc_merge3(VALUE obj, VALUE h1, VALUE h2)
{
VALUE keys;
VALUE akey;
keys = rb_funcall(h1, rb_intern("keys"), 0);
while (akey = rb_each(keys)) {
rb_hash_aset(h2, akey, rb_hash_aref(h1, akey));
}
return h2;
}
void
Init_hello()
{
rb_mHello = rb_define_module("Hello");
rb_cMyCalc = rb_define_class_under(rb_mHello, "Calculator", rb_cObject);
rb_define_alloc_func(rb_cMyCalc, calc_alloc);
rb_define_method(rb_cMyCalc, "initialize", calc_init, 0);
rb_define_method(rb_cMyCalc, "merge", calc_merge, 2);
rb_define_method(rb_cMyCalc, "merge2", calc_merge, 2);
rb_define_method(rb_cMyCalc, "merge3", calc_merge, 2);
}
# test.rb
require "hello"
h1 = Hash.new()
h2 = Hash.new()
1.upto(100000) { |x| h1[x] = x+1; }
1.upto(100000) { |x| h2["#{x}-12"] = x+1; }
c = Hello::Calculator.new()
puts c.merge(h1, h2).keys.length if ARGV[0] == "1"
puts c.merge2(h1, h2).keys.length if ARGV[0] == "2"
puts c.merge3(h1, h2).keys.length if ARGV[0] == "3"
これでテストの結果:
$ time ruby test.rb
real 0m1.021s
user 0m0.940s
sys 0m0.080s
$ time ruby test.rb 1
200000
real 0m1.224s
user 0m1.148s
sys 0m0.076s
$ time ruby test.rb 2
200000
real 0m1.219s
user 0m1.132s
sys 0m0.084s
$ time ruby test.rb 3
200000
real 0m1.220s
user 0m1.128s
sys 0m0.092s
は、それは我々が0.2秒操作に〜最大で0.004sを剃り落とす可能性があるように見えるようにします。
おそらく多くの値を設定する以外に存在しないことを考えると、さらなる最適化のためにそのくらいのスペースがないかもしれません。たぶん、Rubyのソース自体をハックしよう - しかし、その時点で、あなたはもう本当に「拡張子」を開発しないのではなく、言語を変更するので、それはおそらく動作しません。
。 ハッシュの参加は、あなたがCの部分で何回も行う必要がある何かである場合は、- そしておそらく内部データ構造を使用して唯一の最終パスでRubyのハッシュにそれらをエクスポートすることは、物事を最適化する唯一の方法だろう<。 / P>
所属していません StackOverflow