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

go語言如何解決并發(fā)問題

探索住宅動(dòng)態(tài)IP:連接世界的無限可能
AI如何對(duì)產(chǎn)品設(shè)計(jì)帶來更多的可能性?
ADS131A02從AIN1P采到的ADC值不準(zhǔn),請(qǐng)問有哪些可能性會(huì)造成這樣的影響?
高通探索收購英特爾芯片設(shè)計(jì)業(yè)務(wù)的可能性
新思科技探索AI+EDA的更多可能性
三星電子積極探討在越南設(shè)立半導(dǎo)體組裝工廠的可能性
三十分鐘入門基礎(chǔ)Go Java小子版

評(píng)論