有時候,我們會想要把別種語言編寫的庫嵌入到自己的程序里。這類需求在程序員之間早已有之,但出于種種原因,這始終是個充滿了危險、恐懼、折磨的艱難過程。
照常來講,如果想從 Go 中調用 Rust 函數,那我們就必須借助 cgo 這樣的跳板。但這樣效果不錯,而且至少比親自編寫 cgo 這樣的工具方便得多。
然而,問題是當我們用 cgo 將 Rust 函數鏈接到 Go 程序時,還得復制 Rust 生成的共享對象。我們沒法把這個共享對象簽入源代碼樹(不同操作系統、不同 CPU 架構的各自系統分發都必須是唯一的,就像常見的動態鏈接二進制文件一樣)。所以雖然有效,但總體來講其開發者體驗很差。這時候就不能簡單 go build,還得記得運行 cargo build --release 并確保生成的.so、.dll 或者.dylib 位于操作系統動態鏈接程序所能讀取的正確路徑。總之,一團亂麻。
為什么要開發 mastosan
Mastodon 的實質就是把素材存儲為 HTML 格式,再將該 HTML 呈現了 API 使用者。HTML 特別適合瀏覽器顯示,但對 bot 來說意義不大。所以如果目標是 Slack webhook,那就不太合適。
下面來看 API 中的素材:
其內容如下所示:
理想情況下,我們當然希望它在 Slack 中也有相同的語義,比如像這樣:
這條鏈接在 Slack 中的顯示效果跟其他超鏈接一樣。但隨著設計復雜度的提升,Mastodon 也會出現某些怪異語義,例如 span 不可見及其他一些煩人的 Slack 顯示錯誤。我們看看以下兩條有什么區別:
很明顯,這兩條跟人類正常思維的契合度就不一樣。
如何實現
UNIX 理念的核心特征之一,在于將程序視為簡單的過濾器。它既能很好地完成一項任務,又允許用戶將其組合為新的、更有趣的形式。如果大家曾經把 curl 和 jq 配合起來執行操作,比如從 JSONFeed 中讀取數據之類,就能理解這類實踐過程:
我用 Rust 編寫了一個小程序,它使用 lol_html 來獲取傳入的 Mastodon 風格 HTML,并發布 Slack 風格的 markdown。用法非常簡單:
就這么簡單。它會接收標準輸入并在此之上返回結果。這跟 WebAssembly 流并不直接映射,除非用 WASI 填補其中的空缺。WASI 為 WebAssembly 程序提供了類似于 POSIX 的環境,大多數基礎功能都可以直接起效,但這里我們只使用到它的兩個主要部分:標準輸入和標準輸出。
在 Go 中,如果將其作為普通的 OS 子進程運行,可以使用以下代碼:
但這仍然要求程序針對本機 OS 和發行版進行編譯,而且必須存在于 $PATH 文件夾內。所以有效,但還不夠完美。
Rust 允許我們使用以下編譯器標記,構建以 WASI 為目標的二進制文件:
這會在./target/wasm32-wasi/release/mastosan.wasm 當中生成一個幾 MB 大小的二進制文件。只要運行它,就能幫我們達成目標。
現在我們需要在 Go 中用這個二進制文件。可行的辦法很多,這里我選擇使用 wazero。它的使用流程類似于帶 os/exec 的子進程,但也略有不同,因為我們嵌入了 WebAssembly。具體方法如下:
意思基本是一樣的:設置環境、加載 WASM 模塊,然后運行。主要區別在于,這里我沒有把二進制文件作為機器碼從磁盤上加載,而是使用 go:embed 將預編譯的 WebAssembly 模塊嵌入到了二進制文件中。也就是說,只要 WebAssembly 模塊的位置符合要求,那生成的 Go 程序就能正常工作。
再快一點
這種實現的主要缺點就是速度略慢。每次調用該函數時,它都必須編譯 WebAssembly 模塊。
Wazero 運行時和編譯后的 WebAssembly 模塊代碼都可以被舉升到包級變量當中,具體如此補丁(https://github.com/Xe/x/commit/b61b59318be6544632ac1f64b1237bb17b2e7a32)所示。這樣就能大大改善速度問題。用了這個補丁,WebAssembly 模塊只會在應用程序啟動時編譯一次。在使用此補丁前,每次運行中的調用大概需要 0.2 秒,而使用補丁后的基準測試結果為:
可以看到,最佳用時從 0.2 秒下降到了 0.3 毫秒,意味著性能至少提升了 1000 倍。這意味著大部分時間可能都花在了 HTML 解析器上,而不是無關緊要的其他部分。
我覺得這不僅能滿足我個人的工作需求,也應該會幫助更多朋友解決難題。后續我還會用更多隨機 Mastodon 消息做實驗,看看它能否滿足要求。這種將兩個不相容的世界融合起來的感受真棒,也期待它能真正在更多實踐場景當中發光發熱。
審核編輯 :李倩
-
操作系統
+關注
關注
37文章
6874瀏覽量
123573 -
Go
+關注
關注
0文章
43瀏覽量
12266 -
函數
+關注
關注
3文章
4344瀏覽量
62861
原文標題:一場實驗:探索Go程序的進化可能性
文章出處:【微信號:AI前線,微信公眾號:AI前線】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論