2011-03-24 13 views
5

我想開發一些圖像處理代碼,我想知道在C++和C#中開發它們是否有很大的區別?在圖像處理項目中選擇C#和C++時應考慮哪些因素?

是否有任何詳細的文檔解釋了在C#中實現什麼是好的,以及在C++中實現的好處是什麼?

據我所知,由於C#代碼在運行之前(使用.NET CLR JIT編譯器)被編譯爲機器代碼,因此如果在代碼開發期間這兩種語言之間應該沒有太大區別,特定的語言表明要實現一個設計模式(例如,使用很多新的而不是使用固定的數組)。

編輯: 有,我沒想到在第一其它一些參數,但現在我在看的時候我讀一些問題的答案: 1 - 這是一個高層次的項目,這意味着我可以問用戶有一臺非常好的電腦(大量的內存和多核處理器) 2-我可以假設用戶有一個非常好的顯卡,所以我可能能夠使用它的GPU進行處理。我認爲WPF對於這種發展是有益的(我是對的!)。有沒有類似的C++庫?我曾與MFC合作過,但我不確定在處理需要顯示圖像的項目時,MFC和WPF一樣好,而GUI非常重要。

+1

裝配遠.. – 2011-03-24 13:34:54

+6

用兩種語言編寫完整的程序。在多個硬件,操作系統和編譯器配置中運行大量自動化測試。丟棄異常值。享受你的答案。 – 2011-03-24 13:35:42

+0

這並不容易。總成本取決於硬件成本,開發時間等等。性能在大多數情況下並不重要,因爲購買另一臺服務器通常更便宜,而不必使用低級語言(需要更多時間)進行編碼。 – jgauffin 2011-03-24 13:36:58

回答

5

。NET IL被編譯爲機器代碼,就像C++一樣。但幾乎都是C++代碼會更快,這是因爲:

  • 編譯時間變成了運行時的一部分(僅一次,但有時這是一個問題)
  • JIT編譯器花費更少的時間在優化比AOT - 編譯器,因爲上面提到的原因。因此JIT生成的代碼通常比較慢。例如,JIT通常不會矢量化任何東西,這對圖像處理很重要。大多數情況下,由於虛擬機的限制,甚至無法生成向量化代碼(Mono.Simd是個例外)。
  • 虛擬機中的語言必須確保程序不會逃離虛擬機。例如,他們必須檢查每個訪問的數組邊界(除非編譯器可以證明索引總是在範圍內;請記住,JIT編譯器不會在這些分析上花費太多時間)。
  • 對於時間要求嚴格的內核,您可以自行插入彙編程序指令。 VM不允許這樣做,因爲彙編程序可能會脫離VM。

在一些情況下託管代碼可以比非託管代碼更快:

  • 甲garbarge集電極允許內存比的malloc更有效地進行分配。但是,除非短時間使用記憶,但是馬克和掃描也需要一些時間。
  • JIT可能會對代碼編寫更多的靜態代碼(例如,它知道虛擬函數的所有可能實現),並在假設不再成立時重新編譯。這在Java HotSpot中完成,但不在Microsoft的JIT和Mono中完成。

摘要:如果執行速度很重要,請使用C++。但是,C#可以快速足夠,因爲Paint.NET顯示。還要考慮用C#編寫代碼的選項,一旦您對某些重要函數的速度不滿意,請在C++/CIL中重新實現它,或使用P/Invoke調用您的優化函數。

+0

Paint.NET的例子可能是這個答案中最有用的部分。 – 2011-03-24 15:15:43

+0

@Mark:信譽歸功於Steve Haigh,他首先提到了Paint.NET – Meinersbur 2011-03-24 15:35:36

0

這取決於你對這兩種語言有多好,如果你真的是圖像處理編程或算法方面的專家,C++會爲你的雜技優化提供更多的自由。但是,如果你不是專家,通過使用高級語言安全自己

+0

好點,錯誤的結論。 **如果您不是專家,請通過重新使用現有的庫來保存自己。** – 2011-03-25 03:47:48

0

,需要考慮幾個因素...

有沒有,你可能要使用的任何庫 - 如果有,他們是.Net那麼這可能會影響您對C#的支持。然而,我認爲可以認爲最密集的數值應用(和圖像處理基本上是在二維矩陣上的數值密集型操作)可以用本地代碼編寫。有一個非常好的例外 - 看看Paint.Net,它幾乎全部用託管代碼編寫,並且具有出色的性能和功能(http://getpaint.net)。

你的應用程序的目的是什麼?如果這是一種「愛好」或學習練習,那麼隨意使用任何你覺得最開心的語言。如果這是一個商業應用程序,我會首先查看庫選項。

3

作爲將圖像處理庫從C++轉換爲C#並完成基準測試的人員,語言對您所做工作速度的影響很小,更重要的是您正在使用的算法以及您正在使用的api操縱圖像(即在窗口中使用位圖上的鎖定位)。由於事實可以讓我在C#中編寫更多並行代碼比使用C++更容易,並且不會被Monitor.Wait卡住(我承認我不是C++線程專家,實際上我不是一個C++線程業餘愛好者),但有很多選項可以輕鬆地並行化操作(在圖形中是相當內在的),從C++轉換爲C#時大大提高了速度(加上只需要擔心關於釋放資源而不是記憶使生活變得更容易)。顯然,如果你對C++非常適應,那麼你可以在C++中編寫更快的代碼,但是你知道C++和SIMD很適合擊敗C#編譯器。我還應該注意到,我們將C++轉換爲C#,假設我們將損失了約10%的速度,我們轉換的原因是添加新功能的時間成本非常高,以至於重寫C#變得值得我們,最終產品速度更快只是一種獎勵(現在我還應該提到,原始庫是在添加到Visual C++的SIMD擴展之前編寫的,因此使用它對原始庫作者是不可用的)。

+0

Hi Kris,這個圖像處理庫可以在任何地方使用嗎? :O – 2011-03-24 17:34:33

+0

不,它是內部的... – 2011-03-25 14:04:04

1

儘管.NET代碼將JIT編譯爲機器代碼是正確的,但您必須認識到,您對該過程幾乎沒有控制權。您無法選擇目標指令集,而託管代碼提倡聲明JIT編譯更加優秀,因爲它可以使用基於每臺機器可用的最快指令集,事實是尚未實現。底線:您可以使用SSE指令編寫C++代碼,這些指令在同一CPU上運行速度比JIT生成的代碼快4倍。


一些其他的事情值得一提:SIMD並行是一個更容易編寫,併爲編譯器優化,多線程相比更容易了很多。 SIMD沒有開銷,但線程同步不是免費的。 SIMD隱藏的陷阱較少,所以線性加速更容易。多線程很容易陷入緩存線共享和爭用。託管語言絕對不會控制虛假共享。

是的,C#讓多線程更容易。不好。 C++使得多線程正確執行變得更加可行,並且您可以從調優單線程代碼中獲得足夠的速度,而您甚至無需處理線程的額外複雜性。

如果你決定自己的最優化,這裏有一些技巧:(在沿線的任何點停止,一旦你已經達到了所需的性能,因爲你越敷越複雜,代碼將出現)

  1. 處理原始數據時,請不要使用某些API來增加間接和抽象化的像素。這不僅會讓你放慢腳步,還會干擾下一批改進。 (Kris alluded to LockBits vs SetPixel,原始圖像訪問的本機例程是GetDIBits

  2. 緩存調整。一個簡單的方法是將你最內層的循環展開16倍左右。然後反轉循環嵌套順序。這將導致處理數據的矩形塊,這些數據通常是相互依賴的,因此您可以爲每個緩存填充多次訪問每段數據。不過,在這個階段使用緩存分析器是件浪費。

  3. 使用SIMD。在每次循環迭代中處理4倍或更多倍的像素。輕鬆取勝。特別是因爲你已經有點展開循環,那些相同的指令只是坐在那裏乞求合併。但是直到你擺脫抽象概念才能完成。

  4. 現在使用緩存分析器。 SIMD讀取與標量指令有明顯不同的特性,所以您應該在SIMD轉換後執行此操作。

  5. 也許多線程。如果問題真的很大。請特別注意緩存行大小。並且儘量不要寫入其他線程也使用的數據。絕對不要從多個線程寫入相同的數據。

相關問題