LANGUAGE/Java & Groovy 2020. 3. 16. 23:09

Groovy

(GString 너는 좀 다를 줄 알았는데..)

Benchmark

어느 분이 Groovy환경에서 다음 3가지 문자열 병합기능의 속도를 체크해주셨다.
(REF: https://github.com/melix/benchmark-groovy-gstring)

  • GString style interpolation
  • + style concatenation
  • usage of StringBuilder instead

결과!

Benchmark                          Mode  Cnt        Score        Error  Units
StringConcat.gstring              thrpt   20  1623731.208 ±  59007.168  ops/s
StringConcat.gstringStatic        thrpt   20  1606414.896 ±  25461.152  ops/s
StringConcat.simple               thrpt   20  1500527.858 ±  11344.617  ops/s
StringConcat.simpleStatic         thrpt   20  1374998.800 ±  42602.172  ops/s
StringConcat.stringBuilder        thrpt   20  5061006.225 ± 223317.988  ops/s
StringConcat.stringBuilderStatic  thrpt   20  7813080.536 ± 180546.293  ops/s

StringBuilder의 간단한 승리이다.. 육안으로 봐도
GString : "A"+"B" : StringBuilder
=
1623731 : 1500527 : 7813080
(몇배지..;;)

OPS란?

Operation per Second로서 초당 수행 횟수, 단위 시간당 처리 횟수로 해석할 수 있다.

위는 특정 시간 단위에 실행한 횟수를 나타태며, Score 가 높은 것이 좋은 것이다.

느낀점..

따져보니 그동안 나는 기능과 생산성 위주의 코딩을 많이 했었다.

문자열 조합시에 StringBuilder를 사용하라는 것은 Java를 교육하는 곳이나 책 등에서 빈번히 일러준다.

그런데도 나는 처음에 속도에 무뎌.. 그냥 잽싸게 + 를 사용하여 빠르게 코딩을 하는 성향이 되었다.

이에대해 최근에 많이 후회하고 있다. 다양한 테스트를 겪고 객관적인 수치들을 보면서.. 뼈저리게 StringBuilder의 성능을 느낀다.

속도가 빠르다는 것은 단순히 우리가 시간을 절약한 것만을 의미 하진 않는다고 생각한다.
이것이 ECO .. 개발자가 행할 수 있는 친환경 패턴이자 지구를 사랑하는 길일 수도 있다...
사람들이 전기를 당연히 여기게 되는 경향이 있는데.. (이런쪽으로 가면 말이 길어지니.. 싹뚝!)

어쨌거나 저쨌거나

혹시 막 Java를 접하고 있다면 한마디 해주고싶다.

"그냥 무조건 StringBuilder에 버릇을 들여보세요."

설명

1. GString

Groovy를 사용할 때 Java와 최대한 호환이 가능하지만 주의해야할 점들이 몇몇 있다.
그중에 하나가 바로 String Literal인데, Java에서 문자열 방식인 Double Quote를 Groovy는 다르게 취급한다.
이를 GString이라 부르며 해당 코드영역에서 사용가능한 변수를 $와 함께 내부에 적으면 자동으로 파싱해주고 코드까지 가능하다.

"${name} Hi GString here."
"What is your id and code?.. ${nickName.trim().toUpperCase()} and ${getCode(id)}"

덕분에 유연하고 짧은 코드로 생산성이 올라가기도 한다.

Java에서 쓰는 일반적인 String Literal 방식을 사용하려면 Single Quote를 사용해야한다.

'Hi normal string'

2. "A"+"B"

일반적으로 사용하게 되는 문자열 조합방식이다.

"A" + "B"

되도록이면.. 아니 무조건 StringBuilder 또는 StringBuffer(동기화Ver)를 사용하자.

설명은 아래에서 하는걸로 퉁치자..

3. StringBuilder

Java에서 String은 Immutable(불변성)의 성질을 띄고 태어났다.
따라서 문자열은 내부적으로 값을 변경할 수 없게 되어있다.
때문에 위의 +방식으로 문자열을 추가/조합 할 때는 새로운 객체를 생성하여 반환한다.
따라서 속도가 느리다! (위의 Benchmark 결과에서 보듯이)
단순히 문자열이 잘 조합되고 있다는 허상을 버려야한다.
떄에 따라서는 이를 보완하는 StringBuilder와 StringBuffer를 사용하자!
때문에 성능이슈가 있다면.. 아니! 웬만하면 StringBuilder를 이용하여 문자열을 조합하는 것이 좋다!!!

4. 대안 on Groovy Code

그래도 Groovy인데 간단하게 문자를 합칠 방법이 없을까?!
Groovy에선 이런 방법도 있다.

'asdf' << "1234" << "0987"

이것은 StringBuffer다.. ㅎㅎ

아래 Test를 참고

@Test
void StringBufferLiteralTest (){
    def ls = ''<<''
    def lse = ''
    //Check 1
    assert ls instanceof StringBuffer
    lse <<=''
    assert lse instanceof StringBuffer
    //Check 2
    ls = ""<<''
    assert ls instanceof StringBuffer
    lse = ""
    lse <<=''
    assert lse instanceof StringBuffer
    //Check 3
    ls = ''<<""
    assert ls instanceof StringBuffer
    lse = ''
    lse <<=""
    assert lse instanceof StringBuffer
    //Check 4
    ls = ""<<""
    assert ls instanceof StringBuffer
    lse = ""
    lse <<=""
    assert lse instanceof StringBuffer
    //Check 5
    assert ('asdf' << "1234" << "0987") instanceof StringBuffer
}

따로 위 표현식 방법으로 Case를 추가하여 내 컴퓨터에서 Benchmark를 해봤다.

Benchmark                            Mode  Cnt        Score        Error  Units
StringConcat.gstring                thrpt   20   836615.413 ±  95390.742  ops/s
StringConcat.gstringStatic          thrpt   20   841453.970 ±  66816.387  ops/s
StringConcat.simple                 thrpt   20   803602.209 ±  12869.850  ops/s
StringConcat.simpleStatic           thrpt   20   736675.108 ±  17871.816  ops/s
StringConcat.stringBuilder          thrpt   20  2973144.436 ±  74812.124  ops/s
StringConcat.stringBuilderStatic    thrpt   20  3961921.314 ±  51815.580  ops/s
StringConcat.groovySBLiteral        thrpt   20  2983610.561 ± 214896.367  ops/s
StringConcat.groovySBLiteralStatic  thrpt   20  3914557.528 ± 309689.716  ops/s

위에 벤츠마크 검사해주신 분의 컴퓨터가 내 컴퓨터보다 좋다는 것을 알 수 있다... (싹뚝!)

가장 아래항목을 보자! groovySBLiteral 항목을 추가하였다.. 뭔 Error가 이리 많지.. 어쨌든 속도는 얼추 비슷하다만..

Reference - 참조