최적화의 황금률은 그렇지 않습니다.
두 번째 황금률은 중요하지 않습니다.
세 번째 황금률은 실제로 질문입니다. 측정 했습니까?
질문에 답하는 것은 팀에서 허용되는 표준이 무엇이든간에 : 이 아닌 다른 코드는 사용하지 않아야합니다. 즉, 훌륭한 팀에서 코드는 모두 비슷하고 지루합니다. 어떤 조치도 제쳐두고 거대한 번쩍이는 표시가 있습니다. "조심해. 규칙에서 예외 다!" - 당신이 정확히 말하고 싶지 않다면, 다른 사람들이 사용하는 것과 같이 가십시오.
지금, 코드 현명한 대답은 컴파일러에 있습니다
import java.util.logging.*;
public class ForLoop {
private static Logger logger = Logger.getLogger("log");
public static void a(Throwable e) {
StackTraceElement elements[] = e.getStackTrace();
for (int i = 0, n = elements.length; i < n; i++) {
logger.log(Level.WARNING, elements[i].getMethodName());
}
}
public static void b(Throwable e) {
StackTraceElement elements[] = e.getStackTrace();
for (int i = 0; i < elements.length; i++) {
logger.log(Level.WARNING, elements[i].getMethodName());
}
}
public static void c(Throwable e) {
StackTraceElement elements[] = e.getStackTrace();
int n = elements.length;
for (int i = 0; i < n; i++) {
logger.log(Level.WARNING, elements[i].getMethodName());
}
}
}
는 a()
및 c()
는 variable assignment 만 다른, 참조, 따라서 것이다 바와 같이
alf-pro:Learning alf$ javap -p -c ForLoop.class
Compiled from "ForLoop.java"
public class ForLoop {
private static java.util.logging.Logger logger;
public ForLoop();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void a(java.lang.Throwable);
Code:
0: aload_0
1: invokevirtual #2 // Method java/lang/Throwable.getStackTrace:()[Ljava/lang/StackTraceElement;
4: astore_1
5: iconst_0
6: istore_2
7: aload_1
8: arraylength
9: istore_3
10: iload_2
11: iload_3
12: if_icmpge 36
15: getstatic #3 // Field logger:Ljava/util/logging/Logger;
18: getstatic #4 // Field java/util/logging/Level.WARNING:Ljava/util/logging/Level;
21: aload_1
22: iload_2
23: aaload
24: invokevirtual #5 // Method java/lang/StackTraceElement.getMethodName:()Ljava/lang/String;
27: invokevirtual #6 // Method java/util/logging/Logger.log:(Ljava/util/logging/Level;Ljava/lang/String;)V
30: iinc 2, 1
33: goto 10
36: return
public static void b(java.lang.Throwable);
Code:
0: aload_0
1: invokevirtual #2 // Method java/lang/Throwable.getStackTrace:()[Ljava/lang/StackTraceElement;
4: astore_1
5: iconst_0
6: istore_2
7: iload_2
8: aload_1
9: arraylength
10: if_icmpge 34
13: getstatic #3 // Field logger:Ljava/util/logging/Logger;
16: getstatic #4 // Field java/util/logging/Level.WARNING:Ljava/util/logging/Level;
19: aload_1
20: iload_2
21: aaload
22: invokevirtual #5 // Method java/lang/StackTraceElement.getMethodName:()Ljava/lang/String;
25: invokevirtual #6 // Method java/util/logging/Logger.log:(Ljava/util/logging/Level;Ljava/lang/String;)V
28: iinc 2, 1
31: goto 7
34: return
public static void c(java.lang.Throwable);
Code:
0: aload_0
1: invokevirtual #2 // Method java/lang/Throwable.getStackTrace:()[Ljava/lang/StackTraceElement;
4: astore_1
5: aload_1
6: arraylength
7: istore_2
8: iconst_0
9: istore_3
10: iload_3
11: iload_2
12: if_icmpge 36
15: getstatic #3 // Field logger:Ljava/util/logging/Logger;
18: getstatic #4 // Field java/util/logging/Level.WARNING:Ljava/util/logging/Level;
21: aload_1
22: iload_3
23: aaload
24: invokevirtual #5 // Method java/lang/StackTraceElement.getMethodName:()Ljava/lang/String;
27: invokevirtual #6 // Method java/util/logging/Logger.log:(Ljava/util/logging/Level;Ljava/lang/String;)V
30: iinc 3, 1
33: goto 10
36: return
static {};
Code:
0: ldc #7 // String log
2: invokestatic #8 // Method java/util/logging/Logger.getLogger:(Ljava/lang/String;)Ljava/util/logging/Logger;
5: putstatic #3 // Field logger:Ljava/util/logging/Logger;
8: return
}
로 컴파일 JVM에서 JITted와 거의 동일하게 작동합니다. b()
은 약간 다릅니다. 여기서는 arraylength
이 루프 내에서 호출됩니다. @thurstycrow 메모는 반드시 성능 문제는 아니지만 그럴 수도 있습니다.
실제 성능과 관련하여 고려해야 할 가치가 있는지 확인해야합니다. 스택 트레이스 을 검사하는 코드는 stacktrace를 반복해서 가져올 것으로 예상되지 않기 때문에 거의 최적화 할 가치가 없습니다.또한 로깅은 배열 길이 검사보다 비용이 많이 든다고 주장합니다.
그러나이 특정 코드를 최적화해야하는 경우를 상상해 보면 던져진 모든 예외를 검사하고 끝내기보다는 너무 느리게하기를 원하는 사용자 지정 모니터링 도구를 작성한다고 가정 해보십시오. 천천히 (스택 트레이스를 수집하는 것은 비용이 많이 들지 않으며 탐색은 일반적으로 비용이 적게 듭니다.) JIT에서 발생할 수있는 모든 것을 고려하여 주위에 주변에이 코드를 포함시켜야하므로 야생에서 측정해야합니다.
하지만 그것은 지루한 대답입니다. 그래서 우리는 그것이별로 의미가 없다는 것을 알고 있더라도 벤치마킹을 해봅니다. 결국, 우리는 할 수 있습니다. 왜 그렇게하지 않습니까? 사용할 수있는 좋은 벤치마킹 도구는 JMH입니다. 자습서를 따라 가서 연주하거나이 해답을 얻을 수 있습니다.
벤치 마크가 될 것
package org.sample;
import java.util.logging.*;
import java.util.*;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Scope;
@State(Scope.Thread)
public class ForLoop {
private static Logger logger = Logger.getLogger("log");
static {
logger.setLevel(Level.OFF);
}
private StackTraceElement elements[] = new Exception().getStackTrace();
@Benchmark
public void a0() {
for (int i = 0, n = elements.length; i < n; i++) {
logger.log(Level.WARNING, elements[i].getMethodName());
}
}
@Benchmark
public void a() {
for (int i = 0, n = elements.length; i < n; i++) {
logger.log(Level.WARNING, elements[i].getMethodName());
}
}
@Benchmark
public void b() {
for (int i = 0; i < elements.length; i++) {
logger.log(Level.WARNING, elements[i].getMethodName());
}
}
@Benchmark
public void c() {
int n = elements.length;
for (int i = 0; i < n; i++) {
logger.log(Level.WARNING, elements[i].getMethodName());
}
}
@Benchmark
public void d() {
for (StackTraceElement e: elements) {
logger.log(Level.WARNING, e.getMethodName());
}
}
@Benchmark
public void e() {
Arrays.stream(elements)
.forEach(item -> logger.log(Level.WARNING, item.getMethodName()));
}
}
(나중에 a0
에 대한 자세한;에 대한-각각의 스트림을 포함과 답변). 우리가 그것을 실행하면,
alf-pro:test alf$ java -jar target/benchmarks.jar -wi 5 -i 5 -t 4 -f 1
# JMH 1.13 (released 41 days ago)
# VM version: JDK 1.8.0, VM 25.0-b70
# VM invoker: /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/bin/java
# VM options: <none>
# Warmup: 5 iterations, 1 s each
# Measurement: 5 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 4 threads, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.sample.ForLoop.a
# Run progress: 0.00% complete, ETA 00:01:00
# Fork: 1 of 1
# Warmup Iteration 1: 139092694.098 ops/s
# Warmup Iteration 2: 130833602.261 ops/s
# Warmup Iteration 3: 121355640.666 ops/s
# Warmup Iteration 4: 114037414.954 ops/s
# Warmup Iteration 5: 110355992.809 ops/s
Iteration 1: 111331613.966 ops/s
Iteration 2: 111401698.736 ops/s
Iteration 3: 108193438.523 ops/s
Iteration 4: 105277721.260 ops/s
Iteration 5: 103549199.780 ops/s
Result "a":
107950734.453 ±(99.9%) 13602765.938 ops/s [Average]
(min, avg, max) = (103549199.780, 107950734.453, 111401698.736), stdev = 3532595.117
CI (99.9%): [94347968.515, 121553500.391] (assumes normal distribution)
# JMH 1.13 (released 41 days ago)
# VM version: JDK 1.8.0, VM 25.0-b70
# VM invoker: /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/bin/java
# VM options: <none>
# Warmup: 5 iterations, 1 s each
# Measurement: 5 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 4 threads, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.sample.ForLoop.a0
# Run progress: 16.67% complete, ETA 00:00:51
# Fork: 1 of 1
# Warmup Iteration 1: 96143259.419 ops/s
# Warmup Iteration 2: 107561397.775 ops/s
# Warmup Iteration 3: 97488364.065 ops/s
# Warmup Iteration 4: 95880266.969 ops/s
# Warmup Iteration 5: 96943938.140 ops/s
Iteration 1: 95208831.922 ops/s
Iteration 2: 94012219.834 ops/s
Iteration 3: 95369199.325 ops/s
Iteration 4: 96090174.793 ops/s
Iteration 5: 90375159.036 ops/s
Result "a0":
94211116.982 ±(99.9%) 8743077.939 ops/s [Average]
(min, avg, max) = (90375159.036, 94211116.982, 96090174.793), stdev = 2270549.576
CI (99.9%): [85468039.043, 102954194.921] (assumes normal distribution)
# JMH 1.13 (released 41 days ago)
# VM version: JDK 1.8.0, VM 25.0-b70
# VM invoker: /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/bin/java
# VM options: <none>
# Warmup: 5 iterations, 1 s each
# Measurement: 5 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 4 threads, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.sample.ForLoop.b
# Run progress: 33.33% complete, ETA 00:00:41
# Fork: 1 of 1
# Warmup Iteration 1: 58778298.331 ops/s
# Warmup Iteration 2: 66786552.916 ops/s
# Warmup Iteration 3: 67834850.418 ops/s
# Warmup Iteration 4: 69421299.220 ops/s
# Warmup Iteration 5: 72392517.533 ops/s
Iteration 1: 70791625.464 ops/s
Iteration 2: 70393808.080 ops/s
Iteration 3: 68931230.026 ops/s
Iteration 4: 67113234.799 ops/s
Iteration 5: 71628641.383 ops/s
Result "b":
69771707.950 ±(99.9%) 6847578.759 ops/s [Average]
(min, avg, max) = (67113234.799, 69771707.950, 71628641.383), stdev = 1778294.458
CI (99.9%): [62924129.192, 76619286.709] (assumes normal distribution)
# JMH 1.13 (released 41 days ago)
# VM version: JDK 1.8.0, VM 25.0-b70
# VM invoker: /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/bin/java
# VM options: <none>
# Warmup: 5 iterations, 1 s each
# Measurement: 5 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 4 threads, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.sample.ForLoop.c
# Run progress: 50.00% complete, ETA 00:00:31
# Fork: 1 of 1
# Warmup Iteration 1: 87120233.617 ops/s
# Warmup Iteration 2: 88506588.802 ops/s
# Warmup Iteration 3: 82506886.728 ops/s
# Warmup Iteration 4: 75379852.092 ops/s
# Warmup Iteration 5: 83735974.951 ops/s
Iteration 1: 80107472.633 ops/s
Iteration 2: 85088925.886 ops/s
Iteration 3: 81051339.754 ops/s
Iteration 4: 85997882.597 ops/s
Iteration 5: 87092494.956 ops/s
Result "c":
83867623.165 ±(99.9%) 11946241.585 ops/s [Average]
(min, avg, max) = (80107472.633, 83867623.165, 87092494.956), stdev = 3102401.003
CI (99.9%): [71921381.580, 95813864.750] (assumes normal distribution)
# JMH 1.13 (released 41 days ago)
# VM version: JDK 1.8.0, VM 25.0-b70
# VM invoker: /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/bin/java
# VM options: <none>
# Warmup: 5 iterations, 1 s each
# Measurement: 5 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 4 threads, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.sample.ForLoop.d
# Run progress: 66.67% complete, ETA 00:00:20
# Fork: 1 of 1
# Warmup Iteration 1: 90916967.864 ops/s
# Warmup Iteration 2: 91629586.405 ops/s
# Warmup Iteration 3: 107866944.554 ops/s
# Warmup Iteration 4: 102023453.435 ops/s
# Warmup Iteration 5: 111336773.130 ops/s
Iteration 1: 107770637.269 ops/s
Iteration 2: 107103283.175 ops/s
Iteration 3: 107545862.850 ops/s
Iteration 4: 113804266.277 ops/s
Iteration 5: 114628060.965 ops/s
Result "d":
110170422.107 ±(99.9%) 14295432.924 ops/s [Average]
(min, avg, max) = (107103283.175, 110170422.107, 114628060.965), stdev = 3712478.533
CI (99.9%): [95874989.183, 124465855.031] (assumes normal distribution)
# JMH 1.13 (released 41 days ago)
# VM version: JDK 1.8.0, VM 25.0-b70
# VM invoker: /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/bin/java
# VM options: <none>
# Warmup: 5 iterations, 1 s each
# Measurement: 5 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 4 threads, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.sample.ForLoop.e
# Run progress: 83.33% complete, ETA 00:00:10
# Fork: 1 of 1
# Warmup Iteration 1: 33385239.816 ops/s
# Warmup Iteration 2: 38698292.771 ops/s
# Warmup Iteration 3: 38876327.513 ops/s
# Warmup Iteration 4: 37957299.742 ops/s
# Warmup Iteration 5: 39190117.656 ops/s
Iteration 1: 38286235.065 ops/s
Iteration 2: 39449652.416 ops/s
Iteration 3: 38541883.894 ops/s
Iteration 4: 40384962.473 ops/s
Iteration 5: 36975457.540 ops/s
Result "e":
38727638.278 ±(99.9%) 4934050.936 ops/s [Average]
(min, avg, max) = (36975457.540, 38727638.278, 40384962.473), stdev = 1281357.359
CI (99.9%): [33793587.342, 43661689.213] (assumes normal distribution)
# Run complete. Total time: 00:01:02
Benchmark Mode Cnt Score Error Units
ForLoop.a thrpt 5 107950734.453 ± 13602765.938 ops/s
ForLoop.a0 thrpt 5 94211116.982 ± 8743077.939 ops/s
ForLoop.b thrpt 5 69771707.950 ± 6847578.759 ops/s
ForLoop.c thrpt 5 83867623.165 ± 11946241.585 ops/s
ForLoop.d thrpt 5 110170422.107 ± 14295432.924 ops/s
ForLoop.e thrpt 5 38727638.278 ± 4934050.936 ops/s
우리는 세 가지 방법은 말 그대로 매우 다른 측정에서 같은 방법으로 결과가 때 몇 번 실행하는 것이 너무 빨리 것을 볼 수 있습니다. 그래서이 예제에서는 여기서 멈출 것입니다. 실제 사례에 대해서는 문제를 일으키는 실제 코드로 자유롭게 선택하십시오.
PS. for-each 및 스트리밍 솔루션이 추가되었습니다. 보시다시피 for each는 거의 동일합니다 (더 읽기 쉽습니다). 스트림이 눈에 띄게 느립니다. 나는이 두 가지 해결책을 위해 독자를위한 연습으로 javap
examination을 남겨두고 있습니다.
TBH'for (int i = 0, n = elements.length; i
@EricZhang 이것을 보았던 튜토리얼에 대한 링크를 게시 할 수 있습니까? – Kayaman
@Kayaman 자바 튜토리얼에서. url은 https://docs.oracle.com/javase/tutorial/essential/exceptions/chained.html –