Project

General

Profile

Actions

Feature #819

closed

Caching Symbol#to_proc

Feature #819: Caching Symbol#to_proc

Added by akai (Shumpei Akai) almost 17 years ago. Updated over 14 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-dev:37265]

Description

=begin
Symbol#to_proc で毎回オブジェクトを生成するのは無駄な気がするので,
いくつかキャッシュしてはどうでしょうか.

require 'benchmark'
N=10000
syms_miss=(1..500).map{|i|"a#{i}".to_sym}syms_hit=[:a]*500
Benchmark.bm do|r|
r.report("miss"){N.times{syms_miss.each{|x|x.to_proc}}}
r.report(" hit"){N.times{syms_hit.each{|x|x.to_proc}}}
end

上のようなベンチマークを取ると,次のようになります.
% ruby_trunk -v
ruby 1.9.1 (2008-12-03 patchlevel 5000 revision 20460) [x86_64-linux]

キャッシュなし
user system total real
miss 9.060000 0.040000 9.100000 ( 9.092981)
hit 9.070000 0.050000 9.120000 ( 9.114511)
キャッシュあり
user system total real
miss 9.260000 0.020000 9.280000 ( 9.282089)
hit 0.750000 0.000000 0.750000 ( 0.757002)

以下パッチです

Index: string.c

--- string.c (リビジョン 20465)
+++ string.c (作業コピー)
@@ -6912,13 +6912,37 @@

  • (1..3).collect(&:to_s) #=> ["1", "2", "3"]
    */

+static VALUE sym_proc_cache=Qfalse;
+#define SYM_PROC_CACHE_SIZE 64
static VALUE
sym_to_proc(VALUE sym)
{

  • return rb_proc_new(sym_call, (VALUE)SYM2ID(sym));
    -}
  • VALUE proc;

  • ID id;

  • long sym_index,proc_index;

  • VALUE *aryp;

  • if(!sym_proc_cache){

  •    rb_global_variable(&sym_proc_cache);
    
  •    sym_proc_cache = rb_ary_new2(SYM_PROC_CACHE_SIZE * 2);
    
  • }

  • id=SYM2ID(sym);

  • sym_index= (id % SYM_PROC_CACHE_SIZE) << 1;

  • proc_index = sym_index | 1;

  • aryp=RARRAY_PTR(sym_proc_cache);

  • if(aryp[sym_index]==sym){

  •    return aryp[proc_index];
    
  • }else{

  •    proc = rb_proc_new(sym_call, (VALUE)id);
    
  •    aryp[sym_index]=sym;
    
  •    aryp[proc_index]=proc;
    
  •    return proc;
    
  • }
    +}

static VALUE
sym_succ(VALUE sym)
=end

Actions

Also available in: PDF Atom