2017年2月27日月曜日

String.formatは遅いのか (Java/Groovy)

String.formatは遅いのか?

ログの出力の際にも、よく使うString.format だが、
使いやすいが故に気にせず使っていたところ、String.formatは遅いという噂を聞いたので、どのくらい遅いのか比較してみた。
どうやら、内部でFormatterのインスタンスが毎回生成されているために遅いそうだ。。

String.formatが遅い理由
http://qiita.com/kawasima/items/d671d9e57ac03f24fbaa
こちらに理由がちゃんと説明されていた。
・・プロファイラってどうやって使うんだろう。笑
俺もプロファイラ使って色々調べたいぜ!
今度勉強してみよう。。

速度計測の為のコード

import groovy.transform.CompileStatic

@CompileStatic
def test1(int n) {
    for (int i = 0; i<n; i++){
        // groovyのGStringを使った文字列作成
        String str = "count: $n"
    }
}

@CompileStatic
def test2(int n) {
    for (int i = 0; i<n; i++){
        // 単純な文字列の連結
        String str = "count: " + n
    }
}

@CompileStatic
def test3(int n) {
    for (int i = 0; i<n; i++){
        // String.formatを使った文字列作成
        String str = String.format("count: %d", n)
    }
}

(1..3).each {
    long processStart = System.nanoTime();

    "test$it"(1000000)

    long processEnd = System.nanoTime();
    int milliSec = (processEnd - processStart) / 1000000

    println "PROCESS_TIME($it): $milliSec[ms]"
}

// ==> PROCESS_TIME(1): 508[ms]
// ==> PROCESS_TIME(2): 293[ms]
// ==> PROCESS_TIME(3): 1588[ms]
100万回ずつ実行してみた結果がこれだ!

そんなに気にする必要は無い?

単純にStringを連結させた場合のおよそ5倍くらいのコストが発生している感じかな〜。
正直、ログの出力程度ではそこまで気にするほどでもないのかなというのが、僕の印象です。
ただ、速度差があるのは確かで、知見としてもっておくことは大事だと思う。
FPSを意識するゲーム実装で、ワンフレームで数万回以上もformatする場合は、単純連結を使うか、Formatterのインスタンスを一つ生成して使いまわした方が良いのは明白だ。

@CompileStaticを付けているほうが早いよ

ちなみに、@CompileStaticを付けているほうが、
test2,3に関しては速度がやっぱり早くなっているぞ。
下記が、@CompileStaticなしで実行した処理時間。
// ==> PROCESS_TIME(1): 493[ms]
// ==> PROCESS_TIME(2): 343[ms]
// ==> PROCESS_TIME(3): 3611[ms]
ない場合は、ある場合とくらべて、
String.formatの処理が2倍以上もかかっている。。

GStringが意外と早い

意外だったのは、GStringの方が、String.formatより早いんだという事だ。
@CompileStaticを付けても速度差はないものの、
どちらにしてもString.formatよりは早いみたい。
groovy使うなら、String.formatは使うなってことだね。
すげーよ、Groovy♪

0 件のコメント:

コメントを投稿