2011-04-05 5 views
4

최근에 JSON을 사용하여 동일한 클래스의 특정 수의 하위 클래스에 대한 구성 매개 변수를 저장하고 있습니다. 균일 한 인터페이스를 유지하기 위해 부모 클래스에 공개 void setParameter(String, String)String getParameter(String) 메소드를 제공했습니다. 각 하위 클래스는 제공된 매개 변수를 원시 형식으로 변환하고이를 사용하여 일종의 계산을 수행합니다.성능 편집증 : Float.parseFloat (String), Integer.parseInt (String)은 얼마나 비쌉니까?

이제 각 매개 변수를 HashMap에 저장 했으므로 각 매개 변수에 대해 올바른 유형의 별도 필드를 유지하는 것이 합리적입니까? String 매개 변수를 필요할 때마다 고유 유형으로 변환하는 데 필요한 계산 오버 헤드는 무엇입니까?

당신이 그것을 테스트 내가 제안 당신에게
Tunnuz

+3

측정 할 수 있습니까? –

+1

Float.parseFloat() 대신 Float.valueOf()를 사용할 수도 있습니다. 간단한 캐싱을 사용하기 때문에 성능이 약간 향상됩니다. – bvk256

+2

@ bvk256 : Float.valueOf는 캐싱을하지 않습니다. javadoc은 제안하지만, (최소한 Sun JDK에서) 소스 코드를 보면, 그렇지 않습니다. 단지 새로운 인스턴스를 만듭니다. 정수형의 valueOf 메서드는 있지만 부동 소수점 형식은 아닙니다. –

답변

5

감사드립니다. 처음부터 데이터를 작성하는 데 Double.toString() 또는 Integer.toString()을 사용했다면이 작업을 여러 번, 여러 번 수행해야하지만 Double.toString()보다 저렴할 수있는 경우 상당히 비싼 작업입니다.

float을 사용하면 결코 반올림 문제가 발생할 수 없다는 것을 알고있는 경우가 아니면 double 만 사용하는 것이 좋습니다. ;)

String을 작성하거나 HashMap에 항목을 추가하는 것만큼이나 비용이 많이 듭니다. 이 일을 피하려는 계획이 아니라면, 나는 그것에 대해 걱정하지 않을 것입니다.

편집 : @Stackers '벤치 마크와 마찬가지로 나는 nanoTime을 (이상 테스트를 실행하고 사용합니다)

int runs = 10000000; 
String val = "" + Math.PI; 
long start = System.nanoTime(); 
for (int i = 0; i < runs; i++) 
    Float.parseFloat(val); 
long time = (System.nanoTime() - start)/runs; 
System.out.println("Average Float.parseFloat() time was " + time + " ns."); 

long start2 = System.nanoTime(); 
for (int i = 0; i < runs; i++) 
    Double.parseDouble(val); 
long time2 = (System.nanoTime() - start2)/runs; 
System.out.println("Average Double.parseDouble() time was " + time2 + " ns."); 

인쇄 BTW

Average Float.parseFloat() time was 474 ns. 
Average Double.parseDouble() time was 431 ns. 

: 내가 직접의 ByteBuffer의 두 배를 읽는 기능이 80ns가 걸린다. 그것은 String을 필요로하지 않으며 어떤 객체도 생성하지 않기 때문에 더 빠릅니다. 그러나 이렇게하는 것은 결코 쉬운 일이 아니며 객체 생성을 피하기 위해 핵심 시스템을 설계해야합니다. ;)

3

측정이 쉽지있는 그대로 : 100.000 반복에 대한

public class PerfTest { 
    public static void main(String[] args) { 
     String val = "" + (float) Math.PI; 
     long start = System.currentTimeMillis(); 
     for (int i = 0 ; i < 100000 ; i++) { 
      Float.parseFloat(val); 
     } 
     System.out.println(System.currentTimeMillis() - start + " ms."); 
    } 
} 

62ms.

+1

+1 : 테스트를 오래 실행했습니다. 최소 초, nanoTime()을 사용하여 평균 시간을 인쇄하십시오. –

+0

실제 측정을 시작하기 전에 마른 실행을하여 JIT 오버 헤드를 측정하지 마십시오. 편집 : – pauluss86

+0

... @ PeterLawrey의 nanoTime() 조언 및 1 천만 반복을 사용하여 별도의 기능에 벤치 마크를 두어 두 번 호출 , 첫 번째 실행은 느린 x86 넷북에서 두 번째 실행보다 일관되게 느린 속도 (~ 20 %)입니다. – pauluss86

3

위의 마이크로 벤치 마크가 약간 안전하지 않은 것처럼 보일 경우 핫스팟이 변경되지 않을 것으로 예상 할 수 있습니다. &은 사용되지 않습니다. 다른 점은 두 가지 구현의 평균값이 절대적으로 근접 할 수 있지만, 1의 값이 다른 값에 비해 매우 나쁜 테일 비용을 갖는 경우가 있다는 것입니다. 90 번째 백분위 수 값은 꽤 비슷하지만 지난 10 %는 훨씬 더 나 빠질 수 있습니다.

예를 들어 매번 다른 값을 사용하도록 변경하고 stderr에 값을 덤프하면 내 상자에서 다소 높은 평균 비용 (값이 재사용되는 경우 ~ 3300ns ~ 2500ns)이 생성됩니다. 측정치가 인위적으로 팽창하기 때문에 실제로 시간을 확보하는 데 약간의 시간이 걸리기 때문에 이것은 다른 게시물보다 훨씬 높습니다. 이것은 좋은 microbenchmark를하는 어려움 중 하나를 보여줍니다.

내가 제시 한 효과를 측정 할 수 없다는 점도 주목할 가치가 있습니다. 그것이 존재했다면 완전히 최적화 된 상태가 될 것이라고 기대할 수 있습니다. 네가 정말 예리하면 LogCompilation을 통해 무슨 일이 벌어지는 지 알 수있을 것 같아.

int runs = 10000000; 
    long totalTime = 0; 
    for (int i = 0; i < runs; i++) { 
     String val = "" + Math.random(); 
     long start = System.nanoTime(); 
     float f = Float.parseFloat(val); 
     long end = System.nanoTime(); 
     System.err.println(f); 
     totalTime += (end-start); 
    } 
    long time = totalTime/runs; 
    totalTime = 0; 
    for (int i = 0; i < runs; i++) { 
     String val = "" + Math.random(); 
     long start = System.nanoTime(); 
     double d = Double.parseDouble(val); 
     long end = System.nanoTime(); 
     System.err.println(d); 
     totalTime += (end-start); 
    } 
    long time2 = totalTime/runs; 
    System.out.println("Average Float.parseFloat() time was " + time + " ns."); 
    System.out.println("Average Double.parseDouble() time was " + time2 + " ns."); 
관련 문제