初識 WebAssembly:靈活、可移植、高性能

在本文中,我將簡單向你介紹 WebAssembly。首先,我們會簡單瞭解彙編語言的歷史,因爲這一語言使得編程更加輕鬆並且提升了生產力。然後,我們就切入正題,瞭解 WebAssembly,包括它是什麼、它解決了什麼問題以及它的工作機制。

彙編語言的歷史

幾十年前,如果你想爲計算機編程,你必須得寫二進制代碼。我們將其稱爲機器碼(machine code),因爲它是計算機的原生語言(也許這將隨着量子計算的興起而改變,但就目前而言,每臺計算機都在二進制代碼上工作)。機器碼可以直接在計算機上運行,不需要編譯器、轉碼器或其他高級操作。

編寫機器代碼並對其進行調試並不是一項簡單的任務,因此計算機專家們意識到他們需要一個更高級的語言來提升生產力並且讓計算機編程更簡單。基於此,彙編語言應運而生。與機器代碼相比,該語言更簡單也更好理解,因爲它使用的指令不是 0 和 1,而是更接近人類語言的指令,如 add、mul、div、mov 等。

爲了翻譯用匯編語言編寫的代碼,你需要一個 assembler 和一個 linker。然而,在彙編語言和機器碼之間仍然存在着 1 比 1 的關係,這意味着一條彙編指令將被翻譯成機器碼中的確切指令。這在高級語言如 C、C++、C# 等中是不存在的。因爲彙編語言非常接近於機器代碼,所以它的速度也非常快(比任何高級語言都快,因爲高級語言需要被編譯)。隨着代碼複雜性的增加,編譯器將越來越難生成高效和優化的機器碼,這意味着性能降低。因此,如果你需要高性能,理想的選擇是彙編語言。

與彙編語言相比,高級語言有其優勢,如提高生產力、更容易維護和具備可移植性,但它們無法與彙編語言的性能優勢進行競爭。

WebAssembly 介紹

現在我們要開始討論的問題是 “什麼是 WebAssembly”。我們可以說,WebAssembly 是網絡應用程序的彙編語言。但這只是部分正確,因爲 WebAssembly 是一種字節碼(byte code),而彙編語言是一種轉換爲字節碼的語言。WebAssembly 試圖創造的是儘可能快地運行的語言,接近彙編的速度,但應用場景在網絡上,因此而得名。

下一個問題是 “爲什麼我們需要 WebAssembly,它能解決什麼問題?” 這時候我們應該提一下 Javascript。不要誤會,Javascript 固然是一種偉大的語言,但在性能方面依舊存在問題。

爲什麼 Javascript 這麼慢?其中一個主要原因是 Javascript 是動態類型的,這意味着一個變量可以存儲任何類型的數據,從簡單的 ints、到字符串,甚至更復雜的類型如數組或對象。這在編寫代碼時可能是一個優勢,但靜態類型的語言,如 C、C++ 等,會產生更有效的機器碼。在這些情況下,編譯器擁有每個變量的類型和大小信息。

Javascript 比 WebAssembly 慢的另一個原因是,它需要更多的步驟來解析它。解析 JavaScript 需要將純文本轉換爲抽象語法樹(AST),然後將其轉換爲二進制表示。WebAssembly 使用二進制格式,這使得解碼的速度更快。WebAssembly 代碼是靜態類型的,所以 Javascript 引擎不需要在編譯時猜測變量的類型。WebAssembly 代碼的優化發生在編譯過程中,所以沒有額外的優化步驟。在下圖中,我們可以看到將 Javascript 或 WebAssembly 轉換爲可執行代碼所需的步驟:

Javascript 旨在僅顯示靜態頁面。它是爲了提供一個操作 DOM 的 API 而創建的,因此沒有考慮到性能。現在,我們在網絡上有很多 CPU 密集型計算,比如物理、人臉檢測,可能還有一些機器學習等,對於這些 CPU 密集型任務,Javascript 已經不夠用了。

另一個問題是,在網絡上,除了 Javascript 之外,您沒有太多選擇。在後端,有多種選擇,如 C、C++、C#、Java 等,但是當涉及到 Web 時,,你就只能用 Javascript 了。當然,還有其他語言,例如 Typescript,但所有這些語言都以某種方式在 Javascript 中進行了轉換或 “轉譯”。

這就是 WebAssembly 所要解決的問題。WebAssembly 這個詞的靈感來自於彙編語言,它在機器碼中生成優化和高速的程序,並且完全在網絡平臺中運行。這意味着你可以將用於 CPU 密集型計算的 WebAssembly 庫(如壓縮、人臉識別和物理學)集成到目前使用 Javascript 進行低強度工作的網絡程序中。

如果我們想盡可能簡單地定義 WebAssembly,那麼可以認爲它是爲瀏覽器編譯的二進制代碼。

除了提高性能,WebAssembly 還有一個重要的特點:它是一個通用的編譯目標。這意味着我們不再依賴 Javascript,我們可以用任何我們想用的語言(C、C++、C# 等)編寫代碼,並將其編譯成 WebAssembly。你可以訪問下方鏈接查看可以用 WebAssembly 編譯的語言列表:

https://github.com/appcypher/awesome-wasm-langs

WebAssembly 工作機制

在 C、C++、C# 等高級語言中,我們編寫的代碼可以在多個處理器上運行,這意味着該代碼擁有可移植性。但我們是如何解決可移植性問題的呢?我們添加了一層抽象,一個 “虛擬處理器”(the interpreter),它解釋中間字節碼,並將其變成與特定處理器兼容的字節碼。在 interpreter 之前或之後,我們可以添加一個優化步驟,但我們現在不想讓步驟變得如此複雜。

在 WebAssembly 中,理念是類似的,但是針對的是不同的瀏覽器而非處理器。

這樣,我們可以用任何高級語言編寫代碼(可以用. wasm 編譯,這是 WebAssembly 二進制代碼的文件擴展名),它就可以在瀏覽器中運行。這意味着 CPU 密集型的算法可以用 C 語言編寫,並在瀏覽器中運行,解決了可移植性的問題,極大地提高了其性能。

這並不意味着我們不再需要 Javascript 了。對於 CPU 密集型的計算,WebAssembly 有巨大優勢。但是它無法直接訪問 DOM,所以它在 DOM 操作方面比 JavaScript 慢,因爲它有額外的 I/O 開銷。

因此,WebAssembly 和 Javascript 的結合是一個強大的工具,因爲 Javascript 可以專注於 DOM 操作,而 WebAssembly 可以處理 CPU 密集型任務。

通常情況下,我們在使用 WebAssembly 時架構如下:

所以,WebAssembly 只是瀏覽器可以下載的另一種文件,而 Javascript 是 WebAssembly 和網絡應用之間的粘合劑。在這種情況下,app.js 可以與 DOM 交互,但它也可以與 WebAssembly 交互,反之亦然。但是,如上圖所示,WebAssembly 不能與 DOM 交互。因此對於動態和交互式 Web 應用程序,我們仍然需要 Javascript。所以,如果我們想用 WebAssembly 來操作 DOM,它就需要與 Javascript 對話,操作 DOM。這就是爲什麼用 WebAssembly 操作 DOM 比直接使用 Javascript 慢的原因。

WebAssembly 的優勢

即使每個人都在談論 WebAssembly 的優勢都會提及性能,但在我看來,這並不是它最大的優勢。當然,在一些特定的使用情況下,WebAssembly 比 Javascript 有更高的性能,但是當涉及到 DOM 時,Javascript 就處於上風了。

在我看來,WebAssembly 帶來的最重要的優勢是可移植性和靈活性。

要在一個設備上運行一個應用程序,它必須與處理器的架構和設備的操作系統兼容。如果沒有可移植性,你必須爲每個處理器架構和操作系統的組合編譯相同的代碼。有了 WebAssembly,只需一個編譯步驟,它就可以在所有瀏覽器上運行。

另一個顯著的優勢是靈活性。在 WebAssembly 之前,我們一直有這樣的挫折感:在網絡上除了 Javascript 之外沒有任何選擇。但有了 WebAssembly,你可以用你喜歡的編程語言編寫代碼,將其編譯爲. wasm(WebAssembly 的擴展名)即可運行。因此,你可以用 C、C++、C#(見 Blazor 項目:https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor)等高級語言編寫網絡應用程序。此外,在優化性能時,可以用更好的語言重寫現有 Javascript 程序中的瓶頸。

總  結

這篇文章介紹了 WebAssembly,它爲什麼被創造出來,它解決了什麼問題,以及它如何解決這些問題。

WebAssembly 是一種偉大的語言,它爲 web 開發開闢了一個全新的世界,因爲程序員可以選擇他們喜歡的任何語言來編寫 web 應用。隨着 WebAssembly 的興起,我們有了其他選擇來構建我們的網絡應用,而不僅僅是 Javascript。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/sfuXGhDSCNxfElx55aboew