كيفية دمج كفاءة اثنين من التجزئة في روبي ج واجهة برمجة التطبيقات؟

StackOverflow https://stackoverflow.com/questions/1256975

  •  12-09-2019
  •  | 
  •  

سؤال

أنا أكتب امتدادا جيم ل Ruby الذي يحتاج حقا إلى دمج اثنين من التجزئة، ولكن وظيفة RB_HASH_MERGE () ثابتة في Ruby 1.8.6. لقد حاولت بدلا من ذلك استخدام:

rb_funcall(hash1, rb_intern("merge"), 1, hash2);

ولكن هذا بطيء كبير جدا، والأداء أمر بالغ الأهمية في هذا التطبيق.

هل يعرف أحد كيفية الذهاب حول أداء هذا الدمج بالكفاءة والسرعة في الاعتبار؟

(لاحظ أنني قد حاولت ببساطة النظر إلى المصدر RB_HASH_MERGE () وتكرارها، لكنها مليئة بالوظائف الثابتة الأخرى، والتي هي أنفسهم مليئة بالوظائف الثابتة حتى الآن حتى يبدو من المستحيل تقريبا فكدوها ... أحتاج إلى طريقة أخرى)

هل كانت مفيدة؟

المحلول

حسنا، يبدو أن وكأنه قد لا يكون من الممكن تحسين داخل 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.004s على عملية 0.2S.

بالنظر إلى أنه ربما لا يكون هناك الكثير إلى جانب تحديد القيم، قد لا يكون هناك مساحة كبيرة لمزيد من التحسينات. ربما حاول اختراق مصدر Ruby نفسه - ولكن عند هذه النقطة، لم تعد تقوم بتطوير "تمديد" حقا، بل تغيير اللغة، لذلك ربما لن يعمل.

إذا كان انضمام التجزئة من الفحص هو شيء تحتاج إلى القيام به عدة مرات في جزء C - فربما يستخدم هياكل البيانات الداخلية وتصديرها فقط إلى روبي تجزئة في المرة النهائية هي الطريقة الوحيدة لتحسين الأشياء.

سكرتير خاص الهيكل العظمي الأولي للرمز المقترض من هذا البرنامج التعليمي الممتاز

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top