아까 쓴 java, ruby, python 속도비교에서 java의 string concat 을 language에서 제공하는 "S = S1 + S2" 형태를 사용했다가 StringBuffer.append()를 쓰는 것과 상상 이상의 속도차이가 난다는 것을 알게 됬다.
무려 65.695/0.187 = 351.310160428 배..
350배가 넘는 저 차이는 어디서 오는 것일까..
s = s1 + i 라는 코드가 어떻게 컴파일되는지 뜯어 보니..
temp sb = new StringBuilder();
sb.append(s1);
sb.append(i);
c = sb.toString();
이렇게 되고 있었다. (예전에는 StringBuffer를 사용했는데 StringBuilder로 바뀌었군... - StringBuffer를 사용하도록 -target 1.3을 주고 컴파일해도 속도는 마찬가지로 느림..)
그렇다면 c = b.append(a); 와 어떤 부분에서 차이가 있을지 고민해 보니 append는 char[] 복사이니 거의 integer operation 이고.. 문제가 될만한 부분은 sb.toString() ...
풀어보면
sb.toString()
= new String(sb)
= new String(sb.getValue())
음.. char type이 오가고 있으니 encoding 변환을 하는 것도 아닐진데.. 300배 차이는 많이 오버인데..
object 생성속도가 느리다는 결론 말고는 없어보인다. memcp가 한두번 더 일어나긴 하지만 300배 차이가 있을것 같지는 않고..
몇가지 테스트를 더 해보니..
for() {
StringBuilder sb = new StringBuilder();
sb.append(b);
sb.append(i);
b = sb.toString();
}
로 하였을 경우동일한 속도(당연하지만..)
StringBuilder sb = new StringBuilder();
for() {
sb.setlength(0);
sb.append(b);
sb.append(i);
b = sb.toString();
}
로 하였을 경우 13초로 감소..
아마 이것은 object 생성보다는 내부 buffer expend 과정이 생략되서일 듯하고..
StringBuilder sb = new StringBuilder();
for() {
sb.append(i);
}
b=sb.toString();
으로 하니까 0.3초대로 감소... 이부분은 string copy 한번 덜 하는 효과...
그런데 이건 반칙이잖아.. 중간에 b = b + i 에서 "b + i"에 해당하는 object 생성을 생략하는 꼴이니까..
결국 memcopy 가 한번도 없는데, 여러번을 해야 하는 상황이 되서 그랬던 모양이다.
결론은 python 이나 ruby compiler/interpreter/vm 이 string을 좀더 똘똘하게 처리한다는 얘기가 되는군...