アクトインディ開発者ブログ

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社の開発者ブログです

Rubyの文字列連結、最速は?

morishitaです。

先日、文字列を繰り返し結合するようなコードを書いていました。
文字列の連結するのに StringIO を利用していました。

イメージとしてはこんな感じですね。

io = String.new
io.write '文字列'
io.write '文字列'
# 〜中略: たくさんの繰り返し 〜
str = io.string

そのコードをレビューしてもらっていたときに次のようなツッコミをもらいました。

String ではなく StringIO を使ってるのってなんでです?
(効率良かったりするのかしら…?)

私の Web エンジニア人生の最初の言語は Java だったのですが、 Java では大量に文字列を連携する場合には StringBufferを使うのが鉄則です。
(しばらく Java から遠ざかっているのですが、今でもそうですよね? )

で、Ruby のStringIOは Java のStringBufferみたいなものかなと思ってこれまでもなんとなく使っていました。

そのときに議論になったのは +演算子による文字列結合はインスタンスがその都度生成するのでダメだろう。
では、StringIO#write; StringIO#string って String#concat より速いの? ということでした。

で、調べました。

インスタンスの生成はどうなっているのか

まずは、インスタンスが変わるのか変わらないのかを次のコードで確認しました。

puts '-- a += b --'
a = 'a'
b = 'b'
puts "a.object_id:        #{a.object_id}"
a += b
puts "(a += b).object_id: #{a.object_id}"

puts "\n-- a.concat b --"
a = 'a'
b = 'b'
puts "a.object_id:            #{a.object_id}"
a.concat b
puts "(a.concat b).object_id: #{a.object_id}"

puts "\n-- StringIO --"
a = StringIO.new
a.write 'a'
b = 'b'
puts "a.object_id:           #{a.object_id}"
a.write b
puts "(a.write b).object_id: #{a.object_id}"

その結果は次の通り。

-- a += b --
a.object_id:        70242235991440
(a += b).object_id: 70242235991280

-- a.concat b --
a.object_id:            70242235990920
(a.concat b).object_id: 70242235990920

-- StringIO --
a.object_id:           70242235990600
(a.write b).object_id: 70242235990600

まあ、予想通り+演算子はその都度インスタンスが生成されるので論外。
StringIOString#concatは変わりません。

ベンチマーク

次のコードで文字列連結の速度を計測。

require 'benchmark'
n = 10000
m = 1000
Benchmark.bm do |r|
  r.report 'String#+' do
    n.times do
      x = ''
      m.times do
        x += 'a'
      end
    end
  end
  r.report 'String#concat' do
    n.times do
      x = ''
      m.times do
        x.concat('a')
      end
    end
  end
  r.report 'StringIO#write' do
    n.times do
      x = StringIO.new
      m.times do
        x.write('a')
      end
      x.string
    end
  end
end

この結果は次の通り。

                  user     system      total        real
String#+        4.120000   0.170000   4.290000 (  4.286334)
String#concat   2.110000   0.000000   2.110000 (  2.112879)
StringIO#write  1.520000   0.010000   1.530000 (  1.528513)

ほほー、StringIO#write速いね。ということでそのプルリクは LGTM となり、マージしてデプロイされました。

でも...

このエントリを書きながら、ふと気になって次も確認してみました。

require 'benchmark'
n = 10000
m = 1000
Benchmark.bm do |r|
  r.report 'String#<<     ' do
    n.times do
      x = ''
      m.times do
        x << 'a'
      end
    end
  end
end

で、その結果。

                  user     system      total        real
String#<<       1.180000   0.000000   1.180000 (  1.185162)

あ…。

まとめ

Ruby の文字列連結の最速は String#<<

最後に

アクトインディではこんな感じでレビューしあいながら開発しています。
一緒にレビューを楽しみながら開発しませんか?

エンジニア募集中です。

actindi.net

VSCodeにGithub純正のプルリクエスト拡張が来た!

morishitaです。

VSCode に Pull Request のコードレビューをサポートする拡張はいくつかありますが、ついに純正が出ました!
まだプレビュー版ですが、インストールして使えます。

VSCode のブログでも紹介されています。

code.visualstudio.com

できること

  • PR のリストの参照
  • PR 内の変更ファイルリストの参照
  • 変更ファイルの参照とコメント登録(markdown サポート)
  • ワンクリックでローカルにチェックアウトもできる。動作確認しやすい

インストール

通常の拡張の様にインストールできます。 次のページのボタンを押すのが手っ取り早いでしょう。

marketplace.visualstudio.com

ログイン

当然ですが、Github へのログインが必要です。

画面の右下に次のダイアログが出るので、sign inボタンをクリックします。

f:id:HeRo:20180911062526p:plain

するとブラウザが開いて、認証を求められます。 f:id:HeRo:20180911062552p:plain

ボタンをクリックして進むと次の表示に変わるので認可する権限を確認してボタンをクリックします。 f:id:HeRo:20180911062625p:plain

使ってみる

試しに Microsoft/vscode-pull-request-github自身のリポジトリを clone して見てみます。

VSCode の Source Controll を開くと、従来からあるローカルの変更リストの下に GITHUB PULL REQUESTS が追加されています。
開くと、いくつかの PR のリストが表示されます。

  • ローカルの PR のブランチ
  • レビューを求められている PR
  • アサインされている PR
  • 自分が作った PR
  • すべて

すべてから1つ選んで、開いてみます。

Description

ここからチェックアウトしたりコメントもできます。
コードレビューするのに特にローカルにチェックアウトする必要はありません。

変更ファイルの参照

GITHUB PULL REQUESTS のDescription の下には変更ファイルがリストアップされます。 オープンなコメントがあるファイルには印が付くようです。

リストからファイルを選択すると、Diff エディタが開いてコードの差分を確認できます。

f:id:HeRo:20180911062704p:plain

おー、コメントが見えます!

エディタ内では変更箇所の行頭をクリックすると入力欄が現れ、コメント可能です。 もちろん、他人のコメントにリプライすることも可能です。

とりあえず使ってみます

まだ、プレビュー版とのことで不具合等あるかもしれませんが、使い始めようと思います。

大きめの PR のレビューではこれまでもローカルにチェックアウトして 使い慣れたエディタでコードを確認して、Web でコメントをしたりしていました。 また、変更箇所の外に影響範囲がありそうな場合もチェックアウトして確認したり、テストを実行したりしていました。

ちょっと面倒だったのですが、これを使えば手間が減ってプルリクエストのレビューが捗りそうです。

最後に

アクトインディではすべての PRをマージするにはレビューが必須でお互いにコードレビューしています。

その中でお互いに学び合ったり、教え合いながら開発を進めています。 そんな開発を一緒にできるエンジニアを募集しています。

actindi.net

Webプログラマーチュートリアル

ニコ生はじめました。komagataです。

新しくtaharaさんをメンバーに加えて、毎日持ち回りでこのブログを更新していくことになりました。

火曜日:komagata
水曜日:masudaさん
木曜日:chibaさん
金曜日:taharaさん

このような曜日担当で更新してきます。忘れていたら罵倒してください・・・。

ほとんどtaharaさんが書いてくれたのですが、Webプログラマーチュートリアルを作りました。

web-programmer-tutorial - Project Hosting on Google Code

何らかのプログラム経験さえあれば、これをみて自習するだけで業務するのに必要なスキルが習得できるように、ゴールと参考URL・書籍の一覧を用意しました。

入社した最初の一ヶ月を研修期間としてこれをやることにしました。(やりながらメニュー自体も改善する)

これならば自宅を警備しながらスキルを付けることが出来るのではないかと期待しております。

OJTのみになってしまっているのを改善したいITベンチャーの方や自宅警備員の方でこれを使ってわからないところがあれば全力で支援いたします。