上一篇文章,咱們經過實例比較了一下C#和Rust的性能表現,應該說在Release模式下面,Rust進行計算密集型的運算仍是有些比較明顯的優點的。那麼,咱們有沒有可能,在C#中作一些快速應用開發,而一些核心的算法用Rust來實現呢?答案是能夠的。css
下面這段代碼,保存在lib.rs文件中html
use std::thread; #[no_mangle] pub extern fn process(){ let handles :Vec<_> =(0..10).map(|_|{ thread::spawn(||{ let mut x= 0; for _ in (0..5_000_000){ x+=1 } x }) }).collect(); for h in handles{ println!("Thread finished with count={}",h.join().map_err(|_| "Could not join a thread!").unwrap()); } println!("done!"); }
這段代碼的幾個關鍵點在於linux
1.聲明爲pub,也就是說要讓外部能夠訪問到算法
2.聲明爲extern,意思應該也是說但願外部能夠訪問windows
3.添加一個標記 #[no_mangle],這個開關聽說是阻止編譯器在編譯的時候,重命名函數。我也還不是很理解,先照這麼作吧多線程
其餘部分就是標準的Rust代碼了函數
默認狀況下,Rust編譯的庫叫作靜態連接庫,若是咱們須要編譯動態連接庫的話,須要在Cargo.toml文件中定義性能
而後,運行cargo build -- release命令生成動態連接庫(dll)ui
咱們在輸出目錄中,能夠看到一個countlib.dll 的動態連接庫文件spa
你能夠將countlib.dll放在C#編譯輸出目錄的根目錄下面
using System; using System.Threading.Tasks; using System.Diagnostics; using System.Threading; using System.Runtime.InteropServices; namespace ConsoleApplication1 { class Program { [DllImport("countlib.dll",CallingConvention= CallingConvention.Cdecl)] public static extern void process(); static void Main(string[] args) { Stopwatch watch = new Stopwatch(); watch.Start(); //Parallel.For(0, 10, i => //{ // var x = 0; // for (int j = 0; j< 5000000; j++) // { // x += 1; // } // Console.WriteLine("線程:{0} 完成計數",Thread.CurrentThread.ManagedThreadId); //}); process();//調用Rust裏面的程序process進行計算 watch.Stop(); Console.WriteLine("耗時:{0}秒", watch.Elapsed.TotalSeconds); Console.Read(); } } }
在Debug模式下面的耗時爲 0.002秒(提高太明顯了吧)
在Release模式下面的耗時爲0.002秒(基本上跟Debug模式不相上下,很神奇嗎)
那麼,這個性能表現,幾乎接近了直接使用Rust的性能,比原先用C#的方式提升了5倍。
如此說來,計算密集型(尤爲是須要用到多線程,多核)的任務,能夠用Rust來編寫,而後在C#中調用。
【特別注意】
cargo build默認狀況下會根據當前計算機的配置進行編譯,例如我是64位的計算機,那麼編譯出來的dll也是64位的,在C#中用的時候,就須要一樣設置爲64位,不然就會出現錯誤
那麼,cargo build是否能夠指定對應的平臺進行編譯呢?能夠經過指定 --target參數來實現,可用的值主要有
x86_64-pc-windows-gnu
i686-unknown-linux-gnu
x86_64-unknown-linux-gnu
詳細能夠參考 http://doc.crates.io/manifest.html
我用下面這樣用就能夠編譯一個通用的dll(既能用於32位,也能用於64位——採用WOW模式)
其實這個編譯選項,相似於咱們在Visual Studio中使用Any CPU進行編譯