在Java中,相同代碼塊的運(yùn)行時(shí)間不同。這是為什么?
基準(zhǔn)測(cè)試錯(cuò)誤。錯(cuò)誤的非詳盡清單:
:?jiǎn)未螠y(cè)量幾乎總是錯(cuò)誤的; :我們可能開(kāi)始使用僅適用于該方法中第一個(gè)循環(huán)的執(zhí)行數(shù)據(jù)來(lái)編譯該方法; :如果循環(huán)編譯,我們實(shí)際上可以預(yù)測(cè)結(jié)果; :如果循環(huán)編譯,我們可以將循環(huán)丟掉這可以說(shuō)是用jmh正確地做到的:
@OutputTimeUnit(TimeUnit.NANOSECONDS)@BenchmarkMode(Mode.AverageTime)@Warmup(iterations = 3, time = 1)@Measurement(iterations = 3, time = 1)@Fork(10)@State(Scope.Thread)public class Longs { public static final int COUNT = 10; private Long[] refLongs; private long[] primLongs; /* * Implementation notes: * - copying the array from the field keeps the constant * optimizations away, but we implicitly counting the * costs of arraycopy() in; * - two additional baseline experiments quantify the * scale of arraycopy effects (note you can’t directly * subtract the baseline scores from the tests, because * the code is mixed together; * - the resulting arrays are always fed back into JMH * to prevent dead-code elimination */ @Setup public void setup() {primLongs = new long[COUNT];for (int i = 0; i < COUNT; i++) { primLongs[i] = 12l;}refLongs = new Long[COUNT];for (int i = 0; i < COUNT; i++) { refLongs[i] = 12l;} } @GenerateMicroBenchmark public long[] prim_baseline() {long[] d = new long[COUNT];System.arraycopy(primLongs, 0, d, 0, COUNT);return d; } @GenerateMicroBenchmark public long[] prim_sort() {long[] d = new long[COUNT];System.arraycopy(primLongs, 0, d, 0, COUNT);Arrays.sort(d);return d; } @GenerateMicroBenchmark public Long[] ref_baseline() {Long[] d = new Long[COUNT];System.arraycopy(refLongs, 0, d, 0, COUNT);return d; } @GenerateMicroBenchmark public Long[] ref_sort() {Long[] d = new Long[COUNT];System.arraycopy(refLongs, 0, d, 0, COUNT);Arrays.sort(d);return d; }}
…產(chǎn)生:
Benchmark Mode Samples Mean Mean error Unitso.s.Longs.prim_baseline avgt30 19.6040.327 ns/opo.s.Longs.prim_sort avgt30 51.2171.873 ns/opo.s.Longs.ref_baseline avgt30 16.9350.087 ns/opo.s.Longs.ref_sort avgt30 25.1990.430 ns/op
在這一點(diǎn)上,您可能會(huì)開(kāi)始懷疑為什么排序Long[]和排序long[]會(huì)花費(fèi)不同的時(shí)間。答案在于Array.sort()重載:OpenJDK通過(guò)不同的算法(使用Timsort的引用,使用雙數(shù)據(jù)點(diǎn)快速排序的基元)對(duì)基元數(shù)組和引用數(shù)組進(jìn)行排序。這是使用選擇另一個(gè)算法的亮點(diǎn)-Djava.util.Arrays.useLegacyMergeSort=true,這又落到了合并排序的參考上:
Benchmark Mode Samples Mean Mean error Unitso.s.Longs.prim_baseline avgt30 19.6750.291 ns/opo.s.Longs.prim_sort avgt30 50.8821.550 ns/opo.s.Longs.ref_baseline avgt30 16.7420.089 ns/opo.s.Longs.ref_sort avgt30 64.2071.047 ns/op
希望這有助于解釋差異。
上面的解釋幾乎沒(méi)有涉及排序的性能。當(dāng)使用不同的源數(shù)據(jù)(包括可用的預(yù)排序子序列,它們的模式和游程長(zhǎng)度,數(shù)據(jù)本身的大小)呈現(xiàn)時(shí),性能會(huì)有很大不同。
解決方法我有下面的代碼。我只想檢查代碼塊的運(yùn)行時(shí)間。錯(cuò)誤地,我再次復(fù)制并粘貼了相同的代碼,并得到了有趣的結(jié)果。盡管代碼塊相同,但運(yùn)行時(shí)間不同。而且codeblock 1 比其他人花費(fèi)更多的時(shí)間。如果我切換代碼塊,(say i move the code blocks 4 to thetop)則代碼塊4將比其他代碼花費(fèi)更多時(shí)間。
我在代碼塊中使用了兩種不同類型的數(shù)組來(lái)檢查它是否依賴于此。結(jié)果是一樣的。如果代碼塊具有相同類型的數(shù)組,則最上面的代碼塊將花費(fèi)更多時(shí)間。參見(jiàn)下面的代碼和給出的輸出。
public class ABBYtest {public static void main(String[] args) { long startTime; long endTime; //code block 1 startTime = System.nanoTime(); Long a[] = new Long[10]; for (int i = 0; i < a.length; i++) {a[i] = 12l; } Arrays.sort(a); endTime = System.nanoTime(); System.out.println('code block (has Long array) 1 = ' + (endTime - startTime)); //code block 6 startTime = System.nanoTime(); Long aa[] = new Long[10]; for (int i = 0; i < aa.length; i++) {aa[i] = 12l; } Arrays.sort(aa); endTime = System.nanoTime(); System.out.println('code block (has Long array) 6 = ' + (endTime - startTime)); //code block 7 startTime = System.nanoTime(); Long aaa[] = new Long[10]; for (int i = 0; i < aaa.length; i++) {aaa[i] = 12l; } Arrays.sort(aaa); endTime = System.nanoTime(); System.out.println('code block (has Long array) 7 = ' + (endTime - startTime)); //code block 2 startTime = System.nanoTime(); long c[] = new long[10]; for (int i = 0; i < c.length; i++) {c[i] = 12l; } Arrays.sort(c); endTime = System.nanoTime(); System.out.println('code block (has long array) 2 = ' + (endTime - startTime)); //code block 3 startTime = System.nanoTime(); long d[] = new long[10]; for (int i = 0; i < d.length; i++) {d[i] = 12l; } Arrays.sort(d); endTime = System.nanoTime(); System.out.println('code block (has long array) 3 = ' + (endTime - startTime)); //code block 4 startTime = System.nanoTime(); long b[] = new long[10]; for (int i = 0; i < b.length; i++) {b[i] = 12l; } Arrays.sort(b); endTime = System.nanoTime(); System.out.println('code block (has long array) 4 = ' + (endTime - startTime)); //code block 5 startTime = System.nanoTime(); Long e[] = new Long[10]; for (int i = 0; i < e.length; i++) {e[i] = 12l; } Arrays.sort(e); endTime = System.nanoTime(); System.out.println('code block (has Long array) 5 = ' + (endTime - startTime));}}
運(yùn)行時(shí)間:
code block (has Long array) 1 = 802565
code block (has Long array) 6 = 6158
code block (has Long array) 7 = 4619
code block (has long array) 2 = 171906
code block (has long array) 3 = 4105
code block (has long array) 4 = 3079
code block (has Long array) 5 = 8210
如我們所見(jiàn),包含的第一個(gè)代碼塊Long array將比包含的其他代碼花費(fèi)更多的時(shí)間Long arrays。包含的第一個(gè)代碼塊也是如此longarray。
任何人都可以解釋這種行為。還是我在這里做錯(cuò)了?
相關(guān)文章:
1. 在Java中System.out.println 只能在method中使用嗎?2. 怎樣在java中查詢mysql得到如下的json格式的結(jié)果?3. 為什么在java中,賦值和數(shù)據(jù)類型一樣的變量i3,i4,System.out.println(i3==i4),最終輸出不相等?4. 在JAVA中生成UUID字符串的有效方法(不帶破折號(hào)的UUID.randomUUID()。toString())5. 在Java中,我們使用Apache Mina, http://mina.apache.org/ 其性能可與C實(shí)現(xiàn)媲美。6. 如何在Java中聆聽(tīng)按鍵時(shí)移動(dòng)圖像。7. 如何在Java中替換字符串中的點(diǎn)(。)8. 我何時(shí)應(yīng)該在Java中使用JFrame.add(component)和JFrame.getContentPane()。add(component)9. 如何在Java中聆聽(tīng)按鍵時(shí)移動(dòng)圖像
