2011-03-20 38 views
0

我在C#創建了以下功能:如何驗證一個函數是否已經在C#中緩存?

float GetPI() 
{ 
    return 22.0f/7.0f; 
} 

void Calculate() 
{ 
    float f1 = GetPI()*4; 
    float f2 = GetPI()*5; 
} 

如果我創建一個發佈版本,我將如何能夠驗證JIT編譯器是否將緩存22/7計算,還是將計算每次調用GetPI函數?

PS:我沒有的Visual C#工作室專業版

編輯:改變22/7至22.0f/7.0f,使例子功能更準確

+2

爲什麼不直接使用'Math.PI':http://msdn.microsoft.com/en-us/library/system.math.pi.aspx – 2011-03-20 23:27:10

+0

提示:你應該有'回報22.0f/7.0f'; – 2011-03-20 23:27:19

+1

3對pi來說是非常不準確的近似值。而不使用已經發明的輪子更糟。更一般地說,除非你有一個很好的理由去做(否則你不太可能!),你應該相信那些讓你的代碼運行的精靈。他們的創造者知道他們在做什麼。 – delnan 2011-03-20 23:27:50

回答

4

我不確定你的意思是被緩存。除非編譯器沒有進行任何常量摺疊(在這種情況下它會這樣做),或者運行時不會內聯你的函數(在這種情況下它可能會),它不會爲你自動執行任何「緩存」。


表達22f/7f爲常量表達式,並且可以在編譯時進行評估(又名,constant folding)。因此,在編譯後的程序集中,它將顯示爲:

float GetPI() 
{ 
    return 3.142857f; // however many digits of precision 
} 

如果有機會,編譯器將始終進行此類優化。除非有一個編譯器選項來禁用它(我不確定是否有)。爲了驗證發生這種情況,可以使用Reflector(如其他人指出的)來查看編譯後的程序集。無論是Debug還是Release版本或使用Express版本(除非明確禁用此優化),您都應該看到它的確在執行此操作。


如果函數是很簡單的,運行時可能會內聯的函數調用。因此,不是調用該函數,而是將結果插入函數調用的位置。看到這只是一個函數,只是返回一些數字,它可能會做這種優化。我不知道是否還有一種方法可以查看是否發生這種情況,而無需通過調試器實際查看JIT編譯的代碼。


如果你的意思是緩存爲memoization,則沒有這將不會自動完成,你就必須這樣做你自己。


如果你想絕對保證編譯器將「高速緩存」(如不重新計算商)的值,你應該聲明你的價值作爲一個常數(或使用現有的,更準確的System.Math.PI常數) 。沒有什麼是在運行時確定的,在編譯時就知道一切。而且每次你​​使用這個值時,都會被「內聯」,所以你不必擔心這一點。

const float PI = 22f/7f; // will be stored as 3.142857f 

// or another way, if you need PI to be a float but want a more accurate value 
const float PI = (float)Math.PI; // will store as much precision possible 
// note that this only works because Math.PI is declared as a constant 
1

下載並安裝.NET反射(原由Lutz Roeder撰寫,現在由Red Gate維護)。如果您不想付費,您可能需要尋找舊版本。

當您在Reflector中打開代碼時,可以看到編譯器做了哪些更改。

這不會顯示你的JIT優化,你需要在調試器中逐句通過機器代碼,但我很確定這種情況將由C#編譯器評估。

+0

不會調試器生成不同的代碼,因爲它將被調試構建? – paseena 2011-03-20 23:37:08

+0

@quantcoder:這取決於我們說的代碼的哪一部分。我不認爲當涉及到將常量的計算更改爲常量結果時,許多編譯器會對發佈版和調試版進行區分。 – steinar 2011-03-20 23:43:51

+1

@quantcoder:你必須將一個發佈版本加載到調試器中,而且你還必須使用「attach to process」,因爲如果該過程是從附加的調試器開始的,那麼也會禁用JIT優化。 – 2011-03-21 00:02:28

1

有很多方法。一個方便的是使用.NET Reflector。

在Reflector中打開你的程序集,選擇C#,在treeview中找到方法,選擇Tools/Disassemble。反彙編器將顯示如下內容:

public float GetPI() 
{ 
    return 3f; 
} 
相關問題