Help us understand the problem. What is going on with this article?

Rubyのcapacityについて

More than 5 years have passed since last update.

Rubyのcapacityについて調べたのでまとめた。

実際のコードはこちらにまとめた。 https://github.com/ksss/capa

背景

golangのsliceはcapacity(以下capa)を指定できる。

a = make([]int, 0, 1000) // 長さ=0,capa=1000のslice

これをRubyでもできたら便利になる場面があるだろうかと思って調べてみた。

目的

あらかじめメモリーを確保しておくmethodを用意することで、速度的に有利になる場面があるのか調査する。
よい結果が出ればRuby調査用gemとしてまとめる。

実験

準備

ruby

$ ruby --version
ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]

コード

Rubyに仮想のmethodArray.new_capaがあったとする。

a = Array.new_capa(1000)

実装イメージ

#include "ruby.h"

static VALUE
rb_s_ary_new_capa(VALUE klass, VALUE capa)
{
  return rb_ary_new_capa(FIX2LONG(capa));
}

void
Init_ext()
{
  rb_define_singleton_method(rb_cArray, "new_capa", rb_s_ary_new_capa, 1);
}

gnuplot

Benchmarkを可視化するためにgnuplotを使用した。

brew install gnuplot

また、gnuplotコマンドラッパー用のgemが便利そうだったので使ってみた。1

gem install gnuplot

結果

n回pushするコードを用意して比べてみた。

初期オブジェクトに0〜10000回、1回刻みでpush回数を変えていった場合のrealtimeとObjectSpace.memsize_of_allをプロットした。

速度

realtime

みにくいが紫色の点がArray.new、緑の点がArray.new_capaで初期オブジェクトを作った場合の結果。

メモリー

memory

メモリーは当然ながら顕著な違いが現れた。

通常のArray.newで作るArrayの初期capaは3である。

そこからpushしていくと容量が足りなくなるのでcapaを増やさなければならない。
しかしながら一づつcapaを増やしてしまうとメモリの再確保回数が多くなってしまうためある程度メモリーを確保してメモリ確保回数を減らしているようだ。

そのため、メモリ確保はどうしても階段状になってしまう。

考察

速度

速度的には今回の計測ではほとんど差はみられないという結果になった。

速度的な性能はreallocによるオーバーヘッドが大きいほど向上し得たとかんがえられるが、その回数があまり多くはないため大した差が産まれなかったものと考えられる。
たとえ差があったとしてもほとんど誤差の範囲なので、このままでは実用的ではないだろう。

メモリー

最初からメモリを確保してしまっているArray.new_capaではメモリの再確保は発生していないので最小限の確保だけで済んでいるようだ。

この特性からメモリーリソースがシビアな場面でわずかに威力を発揮することがあるかもしれない。

とはいえArray.new(n)等で最初から指定した大きさのArrayを作っておき、pushではなく[]=をつかうことで、
指定したメモリー量でオブジェクトを作ることは可能なので通常はこちらを使えば問題ないだろう。2

更に調査したいこと

プロットの分散具合

速度グラフをよく見ると、全体的に線形に広がっていっているようにみえる。ほとんどのプロットは下端に集まっているのに対して、上端にも少量のプロットが集まっているように見受けられる。
単純に誤差なのであればコードの実行回数が増えてもまんべんなく広がるように予想されるが、上端に集まるのであれば、特定の条件下で少しだけ性能が劣化するタイミングがあるのかもしれない。

ケース

capaをあらかじめ確保しておいたほうが有利になる場合が他にあるかも知れない。
が、現状思いつかない。

まとめ

結果としてはgolangのようにcapaを指定できる方法がRubyにもあったとしても、ほとんど優位にはならないことがわかった。

したがってこのようなGemを作ることは現状無意味だろう。

というわけでRubyはよくできててすごい


  1. 最近はあんまりアップデートされていないようだ 

  2. 実際にプロットしてみたが予想通り線形のプロットとなり、まったく差が見られなかった 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした