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

昔の記事の引越しです。

String.formatは遅いのか?

ログの出力の際にも、よく使うString::format ですが、
使いやすいが故に気にせず使っていたところ、String.formatは遅いという噂を聞いたので、
どのくらい遅いのか比較してみた。

どうやら、内部でFormatterのインスタンスが毎回生成されているために遅いようです。。

String.formatが遅い理由

http://qiita.com/kawasima/items/d671d9e57ac03f24fbaa
こちらに理由がちゃんと説明されていた。

・・プロファイラってどうやって使うんだろう。笑
俺もプロファイラ使って色々調べたいぜ!

実行環境

Java: 10
Groovy: 2.4

$ java -version
java version "10" 2018-03-20
Java(TM) SE Runtime Environment 18.3 (build 10+46)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10+46, mixed mode)
$ system_profiler SPHardwareDataType
  Processor Name: Intel Core i7
  Processor Speed: 2.7 GHz
  Number of Processors: 1
  Total Number of Cores: 4
  Memory: 16 GB

速度計測

テストコード

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)
    }
}

測定コード

long processStart = System.nanoTime();

// それぞれ、100万回ループの処理時間測定
test1(1000000)
//test2(1000000)
//test3(1000000)

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

println "PROCESS_TIME: $milliSec[ms]"

測定結果

100万回ずつ実行してみた結果がこれだ!

処理時間
test1 GString 489[ms]
test2 文字列連結 355[ms]
test3 String::format 1311[ms]

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

単純にStringを連結させた場合のおよそ5倍くらいのコストが発生している感じかな〜。
正直、ログの出力程度ではそこまで気にするほどでもないのかなというのが、僕の印象です。
ただ、速度差があるのは確かで、知見としてもっておくことは大事だと思う。

FPSを意識するゲーム実装で、ワンフレームで数万回以上もformatする場合は、単純連結を使うか、
Formatterのインスタンスを一つ生成して使いまわした方が良いと思う。

@CompileDynamicの場合

Groovy では、@CompileStaticを付けているほうがもちろん早くなる。
下記が、 @CompileDynamic (@CompileStaticなし)で実行した処理時間。

処理時間
test1 GString 480[ms]
test2 文字列連結 409[ms]
test3 String::format 1519[ms]

GStringが意外と早い

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

コメントを残す