2011-03-21 81 views
16

我知道不安全的代碼更適合訪問像Windows API之類的東西,並執行不安全的類型轉換,而不是編寫更高性能的代碼,但我想問問你是否注意到任何重大的性能改進與安全的c#代碼相比,使用它的真實世界的應用程序。真正不安全的代碼性能

+0

P/Invoke與'unsafe'不太一樣......我不確定推理如下...另外:你是否測量了一下,看看你是否在做一些有用的事情? – 2011-03-21 07:21:02

+1

既不安全也不安全的應該是事實上更高性能的。總體性能取決於您在代碼中實現的算法。 – zerkms 2011-03-21 07:22:11

+2

我現在沒有使用不安全的代碼。我只是想了解是否值得將代碼的關鍵部分更改爲不安全的代碼。 – Miguel 2011-03-21 07:23:49

回答

13

一個很好的例子是圖像處理。通過使用指向字節的指針(這需要不安全的代碼)來修改像素速度要快很多。

實施例:http://www.gutgames.com/post/Using-Unsafe-Code-for-Faster-Image-Manipulation.aspx

如此說來,對於大多數情況,差異不會像明顯。因此,在使用不安全的代碼之前,請對應用程序進行配置以查看性能瓶頸的位置,並測試不安全的代碼是否是真正的解決方案,以使其更快。

+5

安全圖像處理也可以相當快。特別是如果您的算法可以寫入以消除邊界檢查。我只使用不安全的代碼將數據從位圖複製到數組中並返回。如果你使用byte [],你甚至可以避免使用'Marshal'函數。 – CodesInChaos 2011-03-21 08:40:37

+1

@ Botz3000:這是一個很好的鏈接(期待閱讀網站的其餘部分),但結論是不健全的。使用'GetPixel'和'SetPixel' _is_真的很慢,但使用'int []'或多或少像使用沒有缺點的指針一樣快。 – 2012-07-10 09:01:06

+0

@CodeInChaos:我必須同意。我得出的結論是唯一受益的方面是複製位圖數據。儘管如此,還沒有嘗試過使用'元帥'。 – 2012-07-10 09:02:28

13

正如其他帖子所述,您可以使用可以在非常專業的環境中使用不安全的代碼,以獲得顯着的性能提升。其中一種情況是迭代數組值類型。使用不安全的指針運算比使用for循環/索引的通常模式快得多..

struct Foo 
{ 
    int a = 1; 
    int b = 2; 
    int c = 0; 
} 

Foo[] fooArray = new Foo[100000]; 

fixed (Foo* foo = fooArray) // foo now points to the first element in the array... 
{ 
    var remaining = fooArray.length; 
    while (remaining-- > 0) 
    { 
     foo->c = foo->a + foo->b; 
     foo++; // foo now points to the next element in the array... 
    } 
} 

這裏的主要好處是,我們已經削減了數組索引完全檢查..

雖然很高性能,這種代碼很難處理,可能是相當危險的(不安全),並且破壞了一些基本的準則(可變結構)。但是,確實有一些場景中,這是合適的......

+4

這種代碼的另一個重大缺陷是C#程序員中很大一部分人不瞭解它或其含義。如果你在一個團隊工作,採用KISS原則... – MattDavey 2011-03-21 09:12:02

+6

你確定這個特定的例子更快嗎? Sun的JVM使用指針算法使這種類型的代碼(Java或Scala)幾乎與C++一樣快;我很驚訝C#實現不會這麼做。 – 2011-03-21 16:16:45

+2

這個特殊的例子,不,因爲編譯器可以確定** i **永遠不會超出數組的邊界,因此跳過數組邊界檢查。但原則依然存在。在我的具體情況下,我有一個使用數組實現的環形緩衝區,以及一個迭代它的獨立Iterator對象。在這種情況下,編譯器無法進行此優化.. – MattDavey 2011-03-21 16:58:52

20

一些性能測量

的性能優勢並不像你想象的那麼大。

我做了一些正常的託管數組訪問與C#中的不安全指針的性能測量。從Visual Studio 2010,.NET 4之外運行構建


結果,使用 任何CPU |發佈基於以下PC規格:基於x64的PC,1個四核處理器。 Intel64家族6型號23步進10 GenuineIntel〜2833Mhz

Linear array access 
00:00:07.1053664 for Normal 
00:00:07.1197401 for Unsafe *(p + i) 

Linear array access - with pointer increment 
00:00:07.1174493 for Normal 
00:00:10.0015947 for Unsafe (*p++) 

Random array access 
00:00:42.5559436 for Normal 
00:00:40.5632554 for Unsafe 

Random array access using Parallel.For(), with 4 processors 
00:00:10.6896303 for Normal 
00:00:10.1858376 for Unsafe 

注意,不安全*(p++)成語居然跑慢。我猜想這打破了一個編譯器優化,它結合了循環變量和安全版本中的(編譯器生成的)指針訪問。

源代碼可在github

+2

-1。當時已經是一個很好的例子,因爲基本上這個試用代碼太簡單了,怎麼不衡量性能。 – TomTom 2014-02-15 09:11:29

+0

@TomTom如何? – 2014-02-17 10:28:13

+4

這太微不足道了。它沒有考慮編譯器可以/可以做的優化。因此,這些數字是否有任何意義尚不清楚。 – TomTom 2014-02-17 10:33:34

1

嗯,我建議閱讀這個博客員額:MSDN blogs: Array Bounds Check Elimination in the CLR

這澄清越界檢查如何在C#中進行。而且,Thomas Bratts測試對我來說似乎沒用(看代碼),因爲JIT無論如何都會在他的「保存」循環中刪除綁定檢查。

+2

你可以在這裏總結這篇文章。如果鏈接變黑,你的回答不會很有幫助。 – ChrisF 2012-09-30 20:32:58

+3

您已經錯過了測試的要點 - 它們不會顯示邊界檢查與不安全的效果。他們要證明邊界檢查經常被優化,而且在這些情況下不安全的代價可能是不值得的。 – 2013-03-25 15:57:48

0

我對視頻操作代碼使用不安全的代碼。 在這樣的代碼中,您希望它在沒有對值進行內部檢查的情況下儘可能快地運行。沒有不安全的屬性,我可能無法跟上30fps或60 fps的視頻流。 (取決於使用的相機)。

但是由於速度它被代碼圖形的人廣泛使用。