2010-11-10 24 views
10

我試圖通過將double包裝到struct中來獲得我稱之爲度量單位系統的內容。我有C#結構,如Meter,Second,Degree等。我最初的想法是,在編譯器被內聯後,所有的性能都與使用double相同。使用C#類型來表示度量單位

我的顯式操作符和隱式操作符都很簡單明瞭,編譯器實際上將它們內聯,但Meter和Second的代碼比使用double的代碼慢10倍。

我的問題是:爲什麼C#編譯器不能使用第二代代碼作爲最佳代碼使用double,如果它內聯任何東西?

其次定義如下:

struct Second 
{ 
    double _value; // no more fields. 

    public static Second operator + (Second left, Second right) 
    { 
     return left._value + right._value; 
    } 
    public static implicit Second operator (double value) 
    { 
     // This seems to be faster than having constructor :) 
     return new Second { _value = value }; 
    } 

    // plenty of similar operators 
} 

更新:

如果結構適合在這裏我也沒問。它的確如此。

我沒問過代碼是否內聯。 JIT確實將其內聯。

我檢查了運行時發出的程序集操作。他們的代碼不同的是這樣的:

var x = new double(); 
for (var i = 0; i < 1000000; i++) 
{ 
    x = x + 2; 
    // Many other simple operator calls here 
} 

像這樣:

var x = new Second(); 
for (var i = 0; i < 1000000; i++) 
{ 
    x = x + 2; 
    // Many other simple operator calls here 
} 

有在拆卸沒有呼叫指令,因此操作實際上是內聯。但差別很大。性能測試表明使用Second比使用double慢10倍。

所以我的問題是(注意!):爲什麼JIT生成IA64代碼是不同的上述情況?可以做些什麼來使結構運行速度提高一倍?似乎沒有理論上的差異,第二,我看到的差異的深層原因是什麼?

+1

是一個'隱式「或」+「運算符? – 2010-11-10 14:04:04

+0

你可能會對這個相關的問題感興趣:http://stackoverflow.com/questions/348853/units-of-measure-in-c-almost – Benjol 2010-11-10 14:09:12

+1

我知道你正在使用C#,但你有沒有考慮過F#?它內置了靜態單元,檢查哪些是你似乎在尋找的東西。請參閱http://stackoverflow.com/questions/40845/how-do-f-units-of-measure-work – 2010-11-10 14:10:41

回答

1

C#編譯器不內聯什麼 - 在JIT 可能做到這一點,但不是義務來。它應該仍然是很多雖然快。我可能會刪除在+隱式轉換,雖然(見下面的構造函數的用法) - 多一個操作者通過看:

private readonly double _value; 
public double Value { get { return _value; } } 
public Second(double value) { this._value = value; } 
public static Second operator +(Second left, Second right) { 
    return new Second(left._value + right._value); 
} 
public static implicit operator Second(double value) { 
    return new Second(value); 
} 

JIT內聯被限制在特定的場景。此代碼是否能滿足他們?很難說 - 但它應該工作和工作足夠快大多數情況下。 +的問題是有一個IL操作碼用於添加雙打;它幾乎做到了沒有工作 - 當你的代碼調用一些靜態方法和構造函數時;即使內聯,總是會有一些開銷。

+0

我沒有將一個'int'封裝到一個結構體中(實現定點),並且當抖動內聯代碼(IMO應該更積極地內聯代碼)時,它會生成完美的彙編代碼。所以如果內聯,可能根本沒有開銷。 – CodesInChaos 2010-11-10 14:46:36

4

這是我的意見,如果你不同意,請寫評論,而不是沉默downvoting。

C#編譯器不內聯它。 JIT編譯器可能,但這對我們來說是不確定的,因爲JITer的行爲並不簡單。

如果是double實際上沒有操作員被調用。操作數使用操作碼add直接添加到堆棧中。在你的情況下,方法op_Add被調用加上三個struct複製到堆棧和從堆棧複製。

要優化它,請用class替換struct開始。它至少會減少副本的數量。

+2

...結構會讓你陷入困境。 – 2010-11-10 14:16:22

+0

爲什麼你想在這裏使用類而不是結構?如果他使用'class',他的appoach(大量的操作符和類型)的問題不會改變,但性能可能會下降很多。 – CodesInChaos 2010-11-10 14:42:48

+0

@CodeInChaos我從不使用'struct'。我真的認爲它只能用於互操作。 「性能可能會下降很多」爲什麼?請解釋。 – Andrey 2010-11-10 16:57:18