1

我最近了解到可以在運行時生成C#代碼,並且希望使用此功能。我有一些代碼可以執行一些非常基本的幾何計算,例如計算線平面交叉,我認爲通過爲某些方法生成專用代碼可以獲得一些性能優勢,因爲許多計算都是針對同一平面執行的,並重新開始。通過專門計算交叉點的代碼,我認爲我應該能夠獲得一些性能優勢。表達式樹vs IL.Emit用於運行時代碼專業化

問題是我不知道從哪裏開始。從閱讀一些博客文章和瀏覽MSDN文檔,我已經遇到了兩種可能的運行時生成代碼的策略:表達式樹和IL.Emit。使用表達式樹似乎容易得多,因爲不需要學習任何有關OpCodes和其他各種複雜的MSIL的知識,但我不確定表達式樹是否與手動生成的MSIL一樣快。那麼對於我應該採用哪種方法,有什麼建議嗎?

回答

4

兩者的性能通常都是相同的,因爲表達式樹內部遍歷和發射爲IL,使用您將使用的相同底層系統函數。從理論上講,使用低級函數可以發出更高效的IL,但是我懷疑會有什麼實際上重要的性能增益。這將取決於任務,但我沒有對發射的IL進行任何實際優化,而表達式樹所發射的IL相比沒有任何實際優化。

我強烈建議使用名爲ILSpy的工具來反編譯CLR程序集。有了這個,你可以看看實際遍歷表達式樹的代碼,並實際發出IL。

最後,一個警告。我在語言解析器中使用了表達式樹,其中函數調用被綁定到在運行時從文件編譯的語法規則。編譯是這裏的關鍵。對於我遇到的許多問題,如果在編譯時知道要實現的內容,那麼通過運行時代碼生成不會獲得太多性能。一些CLR JIT優化對於動態代碼也可能不可用。這只是我實踐中的一個觀點,而你的領域會有所不同,但如果性能至關重要,我寧願看看本機代碼,高度優化的庫。如果不使用LAPACK/MKL,我已經完成的一些工作會很慢。但那只是一個沒有要求的建議,所以要拿下一點鹽。

+2

我想補充一點,編寫你自己的IL充滿了錯過C#編譯器可能找到的優化的機會。您可能想要發出實際的C#,並使用C#編譯器生成您的結果程序集:http://msdn.microsoft.com/en-us/library/microsoft.cscrp.cfrprocode.aspx – 2012-01-15 02:48:54

+0

@ChrisShain,不幸的是,C#編譯器沒有做任何有趣的可能優化。由於某種原因,甚至C++/CLI也做得更多。這就是爲什麼我更願意自行生成代碼,繞過C#有限優化功能。有些東西很容易實現,但在C#中缺少 - 適當的常量傳播,常量參數專業化(帶內聯),區域分析和分配消除,循環展開,變量合併,循環不變吊裝等。 – 2012-01-18 10:51:14

+2

C#編譯器不會執行這些優化,是否這個責任在JIT編譯器中。這裏的推理是通過將諸如循環展開的優化移動到JIT編譯器,它們被應用於所有的.NET語言。當然,JIT編譯器不會循環展開,內聯和更多。 – 2013-10-28 10:07:51

2

如果我處於您的情況,我會嘗試從高層次到低層次的替代方案,增加「所需時間&工作量」並降低重用性順序,並且只要表現足夠好,我就會停下來是的,即:

  • 首先,我會檢查,看看是否Math.NET,LAPACK或一些類似數字圖書館已經擁有類似的功能,或者我可以適應/代碼延伸到我的需要;

  • 秒,我會嘗試Expression Trees;

  • 第三,我會檢查Roslyn Project(即使它是在預發佈版本中);

  • 第四,我會考慮用不安全的C代碼編寫常見的例程;

  • [第五,我想在不同的行業:)退出並開始一個新的職業],

  • 且僅當這些都不工作了,我會這麼絕望的嘗試發射IL在運行時。

但也許我偏向低級別的方法;你的專業知識,經驗和觀點可能會有所不同。

+1

發射il是###中的一個主要痛苦,但你會學到很多關於clr的內部工作原理! – Peter 2012-07-14 10:42:18