試試將.NET7編譯為WASM并在Docker上運行

之前有聽到說Docker支持Wasmtime了,剛好.NET7也支持WASM,就帶大家來了解一下這個東西,順便試試它怎么樣 。
因為WASM(WebAssembly) 一開始是一個給瀏覽器的技術,比起JS解釋執行,WASM能用于提升瀏覽器的用戶體驗 , 因為在一些場景中它有著比JS更好的性能 。
大家可以將WASM理解為C#的MSIL或者Java的字節碼,它并不是二進制代碼,還是會由JIT編譯執行,JIT有很多優化,另外大多數場景也只會JIT一次,加上省略了JS加載,語法分析各種的過程,才會有著比JS更好的性能 。
另外因為WASM是中間碼的格式,所以理論上任何語言C#、RUST、Java、Go都可以將代碼編譯為WASM,然后放到瀏覽器中執行 。比如C#火熱的Blazor項目,就是將C#編譯為WASM,然后使C#代碼能在瀏覽器中運行 。
另外聊一聊WASI(WebAssembly System Interface),我們知道WASM有著不錯的可移植性和安全性(目前瀏覽器運行都是沙箱運行 , 對于權限管控很嚴格),那么就有一群大佬就說,我們是不是能脫離瀏覽器單獨運行WASM程序呢?于是就產生了一個標準的系統接口 , 大家都按照這樣的方式來生成WASM,調用系統API,然后我們開發一個Runtime,讓大家的WASM程序都能在這上面運行 。
舉個不嚴謹的例子說明一下WASI就是比如:

  • C# => MSIL => CLR(Mono、CoreCLR)
  • Java => 字節碼 => JVM(HotSpot VM、ZingVM)而現在我們可以:
  • C# => WASM => WASI(wasmtime、wasmedge) 。
各位應該就明白了,WASI其實就是個運行時的規范,大家編譯成WASM放上去就能跑 。
試試將.NET7編譯為WASM并在Docker上運行

文章插圖
所以現在對于它的觀點就是,覺得它在Server后端領域目前來說不是一個很價值的東西,因為可移植性好的語言比比皆是,比如C#、Java、Go等等 。
拿性能來說 , 對于這樣的中間語言性能無關就是JIT和GC,WASI的JIT和GC能做的像C#、Java這樣的JIT、GC性能那么好嗎?這個目前來說是存在疑問的,至少在短時間內很難追平其它平臺十多年的優化 。
再說WASM的另一個優點 , 就是體積小和啟動快,現在C#支持NativeAOT、Java有GraalVM、Go和Rust之類的本身就是編譯型語言,啟動速度和體積都很不錯,WASM在這個方面其實不占優勢 。
.NET編譯為WASM好了,言歸正傳,我們來試試.NET7上面的WASM 。.NET7目前已經發布 , 我們需要使用最新的版本,如下圖所示:
試試將.NET7編譯為WASM并在Docker上運行

文章插圖
然后我們創建一個簡單的控制臺項目,用于輸出斐波那契數列和執行耗時,代碼如下所示 (這并不性能最優的實現,只是這樣子實現簡單):
using System.Diagnostics;namespace PublishDotNetToWASM;public static class Program{public static void Main(){// warmulong sum = 0;foreach (var i in Fibonacci().Take(1000)){sum += i;}// runsum = 0;var sw = Stopwatch.StartNew();foreach (var i in Fibonacci().Take(100000)){sum += i;}sw.Stop();Console.WriteLine($"Result:{sum}, Timespan:{sw.ElapsedTicks} Ticks");}private static IEnumerable<ulong> Fibonacci(){ulong current = 1, next = 1;while (true){yield return current;next = current + (current = next);}}}接下來為了將.NET程序發布成WASM , 我們需要安裝Wasi.Sdk預覽包,這個預覽包是Steve Sanderson大佬做的支持,可以將.NET程序編譯為WASM,截止至目前版本信息如下所示:
<PackageReference Include="Wasi.Sdk" Version="0.1.2-preview.10061" />運行dotnet publish -c Release命令,將我們的應用程序發布為WASM格式,在發布過程中,需要下載MinGW作為編譯器,網絡環境不好的同學 , 需要使用proxy,稍微等待一會就順利的發布成功了:
試試將.NET7編譯為WASM并在Docker上運行

文章插圖
運行WASM程序此時我們可以安裝一下Wasmtime來執行我們的程序 , 通過https://wasmtime.dev/下載安裝:
試試將.NET7編譯為WASM并在Docker上運行

文章插圖
然后就可以直接使用wasmtime命令運行我們的程序 , 我分別使用wasmtimedotnet運行了我們的程序:
試試將.NET7編譯為WASM并在Docker上運行

文章插圖
可見目前來說WASM的性能還是慘不忍睹的,等一等后續的優化吧 。
將.NET發布到Docker WASI再來看看我們的Docker,對于Docker支持WASI我感到并不意外,因為Docker的容器化對于直接執行的WASM來說還是比較重,支持它是一個拓寬影響力的好事 。具體的執行模型如下所示,對于WASM應用有著不同的執行方式 。不再使用

推薦閱讀