Go 還是 TinyGo?
什麼是 TinyGo?TinyGo 與 Go 有何不同? TinyGo 與 Go 相比性能如何?
什麼是 TinyGo?
TinyGo 不是另一種編程語言。它只是 Go 語言的一個編譯器。關鍵區別在於 TinyGo 編譯器創建的二進制文件更小, 主要用於嵌入式系統和 WASM。而 Go 編譯器則用於編譯完整的服務器端應用程序和通用程序。
TinyGo 使用 LLVM 作爲後端, 與 Go 編譯器相比可以創建更小的二進制文件。例如, 一個簡單的打印 "Hello World" 的代碼用 Go 編譯可能會產生約 800 KB 的二進制文件大小, 而 TinyGo 在去除不必要的符號後可以將其減少到約 10 KB。
TinyGo 專門用於資源有限的環境, 允許開發人員在各種微控制器和小型設備 (如 Arduino 和 Raspberry Pi) 上運行 Go 代碼, 這些設備通常不受標準 Go 編譯器支持。
TinyGo 的特性和限制
- Cgo
雖然 TinyGo 嵌入了 Clang[1] 編譯器來解析 import"C"
塊, 但 Cgo 的一些功能仍不受支持或可能工作方式略有不同。例如, #cgo
語句只得到部分支持。
- 反射
許多包, 特別是標準庫中的包, 依賴反射來工作。reflect
包在 TinyGo 中已經重新實現, 大部分功能都可以使用, 但有些部分尚未完全支持。
- 映射
映射通常工作正常, 但可能比你預期的要慢。這有幾個原因, 其中之一是某些類型 (如結構體) 可能在內部使用反射進行比較, 而不是使用專用的哈希 / 比較函數。
- 標準庫
由於上述缺失的部分, 以及因爲標準庫的部分依賴於所使用的特定編譯器 / 運行時, 許多包尚未編譯。請參閱 這裏的可編譯包列表 [2] (但請注意,"可編譯" 並不意味着完全可用)。
- 垃圾回收
垃圾回收通常工作正常, 但在非常小的芯片 (AVR) 和 WebAssembly 上可能效果不佳。它也比通常的 Go 垃圾回收器慢得多。仔細的設計可以避免在主循環中進行內存分配, 這可能會大大降低性能。你可以使用 -print-allocs=.
選項編譯, 以瞭解內存分配發生的位置和原因。有關更多信息, 請參閱 堆分配 [3] 。
要了解更多關於語言支持的信息, 請查看 這裏 [4] 。
- 全局變量
TinyGo 在編譯期間計算全局變量, 這可以優化啓動時間並減少內存使用, 而 Go 編譯器則以不同方式處理全局變量。這是一個重要的優化, 原因如下:
-
啓動時間減少。這很好, 但不是主要原因。
-
通過將初始數據從閃存複製到 RAM 來初始化全局變量, 所需的閃存空間要少得多, 因爲只需存儲實際數據, 而不是所有初始化這些全局變量的指令。
-
數據通常可以靜態分配, 而不是在啓動時動態分配。
-
無用的全局變量可以被 LLVM 輕鬆優化掉。
-
常量全局變量可以被 LLVM 輕鬆識別並標記爲
constant
。這確保它們可以存儲在閃存而不是 RAM 中。 -
全局常量對於常量傳播和死代碼消除 (如依賴全局變量的
if
語句) 很有用。
附加內容
我比較了使用 Go 和 TinyGo 編譯的 WASM 與 JavaScript 的性能, 結果令人驚訝。在發現 TinyGo 之前, 我對 Go WASM 並不太滿意。我將在下一篇博客中分享完整的教程和我的發現。
結論
總而言之,TinyGo 通過使 Go 能夠在受限環境中運行,擴展了 Go 的能力,同時犧牲了標準 Go 編譯器中的一些功能和性能優化。它對於針對物聯網設備和 WebAssembly 應用程序的開發人員特別有用,因爲在這些場景中,二進制文件大小和資源效率至關重要。
參考鏈接
-
Clang: https://clang.llvm.org/
-
這裏的可編譯包列表: https://tinygo.org/docs/reference/lang-support/stdlib/
-
堆分配: https://tinygo.org/docs/concepts/compiler-internals/heap-allocation/
-
這裏: https://tinygo.org/docs/reference/lang-support/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/wBlBbhNjYvim3wVrQfYOtg