1.8.7でto_proc
実装はこのようになります(object.c
を参照してください):
static VALUE
sym_to_proc(VALUE sym)
{
return rb_proc_new(sym_call, (VALUE)SYM2ID(sym));
}
1.9.2実装のに対し(string.c
を参照)のようになります。あなたはアルを剥ぎ取る場合
static VALUE
sym_to_proc(VALUE sym)
{
static VALUE sym_proc_cache = Qfalse;
enum {SYM_PROC_CACHE_SIZE = 67};
VALUE proc;
long id, index;
VALUE *aryp;
if (!sym_proc_cache) {
sym_proc_cache = rb_ary_tmp_new(SYM_PROC_CACHE_SIZE * 2);
rb_gc_register_mark_object(sym_proc_cache);
rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil);
}
id = SYM2ID(sym);
index = (id % SYM_PROC_CACHE_SIZE) << 1;
aryp = RARRAY_PTR(sym_proc_cache);
if (aryp[index] == sym) {
return aryp[index + 1];
}
else {
proc = rb_proc_new(sym_call, (VALUE)id);
aryp[index] = sym;
aryp[index + 1] = proc;
return proc;
}
}
リットル、あなたが(多かれ少なかれ)を残しているsym_proc_cache
を初期化するの忙しい仕事、この:1.8.7は、ブランドの新しいを生成しながら、
aryp = RARRAY_PTR(sym_proc_cache);
if (aryp[index] == sym) {
return aryp[index + 1];
}
else {
proc = rb_proc_new(sym_call, (VALUE)id);
aryp[index] = sym;
aryp[index + 1] = proc;
return proc;
}
だから本当の違いは、1.9.2のto_proc
キャッシュ生成手続きオブジェクトであります1回毎にto_proc
と呼んでいます。これらの2つのパフォーマンスの差は、各反復が別のプロセスで行われない限り、ベンチマークによって拡大されます。ただし、プロセスごとに1回反復すると、開始コストでベンチマークしようとしていることが隠されます。 rb_proc_new
の
根性はほとんど同じに見える(1.8.7または1.9.2のためのproc.c
ためeval.c
を参照)が、1.9.2はrb_iterate
のいずれかの性能向上から、わずかに受けることができます。おそらくキャッシュは大きなパフォーマンスの違いです。
シンボル・ハッシュ・キャッシュは固定サイズ(67エントリですが、どこから来たのか分かりませんが、シンボル・ハッシュ・キャッシュによく使用される演算子の数に関係します-PROCの変換):あなたは、シンボルIDの重複(MOD 67)procsのよう場合、または以上の67個の記号を使用している場合
id = SYM2ID(sym);
index = (id % SYM_PROC_CACHE_SIZE) << 1;
/* ... */
if (aryp[index] == sym) {
は、あなたはキャッシュの完全な利益を得ることはありません。
Railsと1.9プログラミングスタイルのような速記の多く含まれます。
かなり長い明示的なブロックの形態よりも
id = SYM2ID(sym);
index = (id % SYM_PROC_CACHE_SIZE) << 1;
を:(人気の)プログラミングスタイル、それは理にかなっていることを考えると
ints = strings.collect { |s| s.to_i }
sum = ints.inject(0) { |s,i| s += i }
ルックアップをキャッシュすることによってメモリを交換することができます。
gemがRubyのコア機能のチャンクを置き換えなければならないため、より速く実装することはできません。 1.8.7のソースに1.9.2のキャッシュをパッチすることができます。
そして、キャッシュが効果的に67個のバケツを持っていることによって動作し、あなたがハッシュにシンボルをオンにし、それが中に行くと思いバケットかを確認し、 'sym'は、そのバケット内にある場合、それはそれでPROCを使用していますそれ以外の場合はそのバケットを変更してそのシンボルと適切なprocを保存します。 –
@Andrew:キャッシュには67バケット、バケットあたり2つの配列エントリがあります(最初のエントリはシンボル、2番目のエントリはprocです)。そして、はい、シンボルが一致しない場合、キャッシュはスロットを再利用します、私はその答えを明確にするために更新します。 –
@Andrew:BTW、過去数日間のRuby内部のツアーのおかげです。 –