簡體   English   中英

在OS X中,為什么使用println()會導致程序比沒有println()運行得更快

[英]In OS X, why does using println() cause my program to run faster than without println()

我遇到了一個非常奇怪的錯誤,我希望這里的某個人可以解決一些問題,因為它已經超出了我的專業領域。

首先,相關背景信息:我在2013年晚些時候使用2.4GHz Haswell CPU在Macbook Pro Retina上運行OS X 10.9.4。 我正在從Oracle使用JDK SE 8u5 for OS X,並且我在最新版本的IntelliJ IDEA上運行我的代碼。 這個bug似乎也只針對OS X,因為我已經在Reddit上發布了關於這個bug的信息,而OS X的其他用戶能夠重新創建它,而Windows和Linux上的用戶,包括我自己,讓程序按預期運行println()版本運行比沒有println()的版本慢半秒。

現在的bug:在我的代碼中,我有一個println()語句,當包含時,程序運行在~2.5秒。 如果我通過刪除它或將其注釋掉來刪除println()語句,程序違反直覺需要更長時間才能運行~9秒。 這是非常奇怪的,因為I / O理論上應該減慢程序速度,而不是讓它更快。

對於我的實際代碼,這是我對Project Euler Problem 14的實現 請記住我還是學生,所以這不是最好的實施:

public class ProjectEuler14
{
    public static void main(String[] args)
    {
        final double TIME_START = System.currentTimeMillis();

        Collatz c = new Collatz();
        int highestNumOfTerms = 0;
        int currentNumOfTerms = 0;
        int highestValue = 0; //Value which produces most number of Collatz terms


        for (double i = 1.; i <= 1000000.; i++)
        {
            currentNumOfTerms = c.startCollatz(i);


            if (currentNumOfTerms > highestNumOfTerms)
            {
                highestNumOfTerms = currentNumOfTerms;
                highestValue = (int)(i);
                System.out.println("New term: " + highestValue); //THIS IS THE OFFENDING LINE OF CODE
            }
        }

        final double TIME_STOP = System.currentTimeMillis();

        System.out.println("Highest term: " + highestValue + " with " + highestNumOfTerms + " number of terms");
        System.out.println("Completed in " + ((TIME_STOP - TIME_START)/1000) + " s");
    }
}


public class Collatz
{
    private static int numOfTerms = 0;
    private boolean isFirstRun = false;

    public int startCollatz(double n)
    {
        isFirstRun = true;
        runCollatz(n);
        return numOfTerms;
    }

    private void runCollatz(double n)
    {
        if (isFirstRun)
        {
            numOfTerms = 0;
            isFirstRun = false;
        }

        if (n == 1)
        {
            //Reached last term, does nothing and causes program to return to startCollatz()
        }

        else if (n % 2 == 0)
        {
            //Divides n by 2 following Collatz rule, running recursion
            numOfTerms = numOfTerms + 1;
            runCollatz(n / 2);
        }

        else if (n % 2 == 1)
        {
            //Multiples n by 3 and adds one, following Collatz rule, running recursion
            numOfTerms = numOfTerms + 1;
            runCollatz((3 * n) + 1);
        }
    }
}

有問題的代碼行已經使用全部大寫字母進行了評論,因為它看起來不像是行號。 如果你找不到它,它在我的main方法的for()循環中的嵌套if()語句中。

我在使用和不使用該行的情況下多次運行我的代碼,並且我一直使用println()和沒有println()的〜9秒來獲得上述約2.5秒的時間。 我還重啟了我的筆記本電腦多次,以確保它不是我當前的操作系統運行和時間保持一致。

由於其他OS X 10.9.4用戶能夠復制代碼,我懷疑這是由於編譯器,JVM或操作系統本身的低級錯誤。 無論如何,這超出了我的知識范圍。 這不是一個關鍵的錯誤,但我肯定對為什么會發生這種情況感興趣並且會欣賞任何洞察力。

我做了一些研究,還有一些關於@ekabanov的研究,以下是研究結果。

  • 您所看到的效果只發生在Java 8而不是Java 7中。
  • 額外的行觸發不同的JIT編譯/優化
  • 更快版本的匯編代碼大約3倍,快速瀏覽顯示它循環展開
  • JIT編譯日志顯示較慢的版本成功內聯runCollat​​z,而較快的版本沒有說明被調用者太大(可能是因為展開)。

有一個很棒的工具可以幫助你分析這種情況,它被稱為jitwatch 如果它是匯編級別,那么您還需要HotSpot反匯編程序

我也會發布我的日志文件。 您可以將熱點日志文件提供給jitwatch,並且您可以區分組件提取以發現差異。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM