안녕하세요.
처음으로 글을 적어 봅니다.
최근에 성능을 조금이라도 더 쥐어 짜내야 하는 앱을 하나 개발하고 있어서
개인적으로 궁금한 점이 많아 이것저것 검색도 해보고 실험도 해본 결과를 간단히 공유하려고 합니다.
(게시판 성격에 잘 맞는지 모르겠습니다. ^^)
사실 프로그래밍에 있어서 기본일 수도 있고, 반대로 틀린 점도 있을 수 있습니다...
제 수준에서 적은 것이니 몇몇 분이라도 참고가 되셨으면 좋겠습니다.
혹시 잘못된 사실이나 다른 의견이 있으시면 답글 부탁드립니다. 제게도 많은 도움이 될 듯 합니다. ^-^
결론부터 정리하겠습니다.
같은 중간 계산 결과가 2번 이상 반복 사용되는 경우는 무조건 임시 변수를 사용하면 손해 볼것은 별로 없습니다.
실질적인 예를 하나 들어보겠습니다.
Android 개발하다보면 다음과 같은 코드를 빈번하게 사용할 수 있습니다.
(아래는 View class를 확장하여 커스텀 view를 만들다가 나오는 코드입니다)
canvas.drawRect(getWidth() - length, 0, getWidth(), getHeight(), paint);
(View 오른쪽을 기준으로 length 길이만큼 사각형을 그려주는 예입니다.)
문제는, 위의 코드에서 getWidth()를 두번 호출하고 있는데 이것을 임시 변수에 저장하는 것이 좋을까요? 아닐까요? 입니다.
그러니까...
1)
canvas.drawRect(getWidth() - length, 0, getWidth(), getHeight(), paint);
2)
final int width = getWidth();
canvas.drawRect(width - length, 0, width, getHeight(), paint);
1)번을 쓸지...
아니면 2)번을 쓸지 고민이 된다는 겁니다.
중간 계산이 굉장히 복잡하다거나,
getWidth()를 코드내에서 한 10번쯤 쓴다고 하면
고민하지 않고 임시 변수를 쓰겠지만...
위와 같은 경우는 왠지 getWidth()라는 함수의 연산이 그리 복잡할 것 같지는 않고,
코드내에서도 2번 밖에 등장하지 않는데,
지역변수를 하나 더 선언하는게 오히려 느리지는 않을까? 고민이 될 수 있습니다.
그래서 직접 테스트를 해보았습니다.
오드로이드, 옵티머스 2X 등 여러 기기에서...
오드로이드 기준으로 수백만회 (몇회인지 까먹었습니다) 반복 연산한 결과를 정리하면 아래와 같습니다.
- 성능 Test 1 -
매우 간단한 연산을 두 번만 사용했습니다.
public int compute1(int a, int b) {
final int minus = a - b;
return (minus - 2) * (minus + 2);
}
public int compute2(int a, int b) {
return (a - b - 2) * (a - b + 2);
}
compute1 평균: 362 ms
compute2 평균: 361 ms
별 차이 없습니다.
- 성능 Test 2 -
매우 간단한 연산을 여러번 사용했습니다.
public int compute1(int a, int b) {
final int minus = a - b;
return (minus - 2) * (minus + 2) * (minus + 10) * (minus - 10) * (minus + 100);
}
public int compute2(int a, int b) {
return (a - b - 2) * (a - b + 2) * (a - b + 10) * (a - b - 10) * (a - b + 100);
}
compute1 평균: 553 ms
compute2 평균: 631 ms
예상했던데로 임시 변수를 쓰는 쪽이 더 빠릅니다.
- 성능 Test 3 -
간단한 getter 메소드 사용.
(getMember() 함수는 아무 연산없이 private member를 반환하기만 합니다)
public int compute1(int a, int b) {
final int member = getMember();
return (member - 2) * (member + 2);
}
public int compute2(int a, int b) {
return (getMember() - 2) * (getMember() + 2);
}
compute1 평균: 552 ms
compute2 평균: 694 ms
이 경우에도 임시 변수를 쓰는 쪽이 더 빠릅니다.
- 성능 Test 4 -
Member 직접 access
public int compute1(int a, int b) {
final int m = this.member;
return (m - 2) * (m + 2);
}
public int compute2(int a, int b) {
return (this.member - 2) * (this.member + 2);
}
compute1 평균: 346 ms
compute2 평균: 364 ms
심지어 이런 경우에도 임시 지역 변수를 쓰는 쪽이 약간 더 빠릅니다.
- 결론 -
사실 이렇게 까지 성능을 짜낼 필요가 있나 싶기는 하지만...
수행속도 면에서 봤을 때, 항상 임시 변수를 써서 손해볼 것은 없어 보입니다.
최소한 "지역 변수 할당의 (속도적) 비용이 오히려 더 크지는 않을까?" 하는 걱정은 붙들어 매셔도 될 듯 합니다.
좋은 정보 감사합니다...
다 아시겠지만 이 글의 연장선으로...
반복문을 사용할 때
for(int i = 0; i < arr.size(); i++) 보다는
int size = arr.size();
for(int i = 0; i < size; i++) 와 같이 하는게 속도가 빠르죠..
for문의 조건 안에 arr.size()가 있으면 반복될때마다 크기를 계산하기 때문에
크기를 미리 변수안에 넣어서 사용하면 크기를 한번만 계산하므로 효율적이죠...
물론 다 아시겠지만...혹시 모르시는 분들을 위해...
Goooooooooooooooooooooooood~
좋은데요..ㅎㅎ 예상만 해 봤지.. 이렇게 차이가 날 줄은 몰랐습니다.
다만.. 사람이 느끼기엔 미비하지많요..--;;
참고로 테스트 3, 4번 같은 경우에는
안드로이드에서 메소드 호출이나 멤버 변수 접근하는데 자체에 시간을 많이 소모하는 것으로 알고 있습니다.
이런 이유로 안드로이드 퍼포먼스 관련 글들을 보면
get, set 메소드 사용을 피하고, 멤버변수를 로컬변수로 한번 설정한 후 사용하라는 내용이 있기도 하지요.
http://developer.android.com/guide/practices/design/performance.html
개발자 사이트에 가서 간만에 읽어보니 재밌는게 많네요.
성능때문에 고민하는 분은 한번 참고해보세요.
근데 사실 개인적으로 몇개 적용해보긴 했는데 몇백만번 불리는거 아니면 티도 안나더라구요;;;
저는 예전부터 두번 이상 사용하면 임시변수를 사용했는데, 확실히 차이가 있군요.
좋은 정보 감사드립니다 :)