新聞中心
盡管這種選擇帶有一定的主觀性,但Go確實是一種非常高效的嵌入式開發(fā)語言,尤其是涉及到網絡編程時。網絡編程在某些時候是遍布每個連接的設備或應用程序的。Go語言由Google創(chuàng)建,起初是為了滿足Google開發(fā)人員的需求,用于面對其生態(tài)系統(tǒng)中爆炸式增長的復雜性。因此,GO語言自面世就遵循了高效編譯、高效執(zhí)行和易于編程這三個原則,這是它較之其他主流語言的優(yōu)勢。

但是,需要強調的是,Go并不能被視為C語言的替代品。很多時候C語言仍是無可替代的,例如實時操作系統(tǒng)和設備驅動程序的開發(fā)。
嵌入式開發(fā)的嚴格要求
建立架構后,Mender產品工程團隊開始評估哪種語言最適合開發(fā) Mender應用程序。該系統(tǒng)由兩部分組成:一是在嵌入式設備上運行的客戶端,二是連接各客戶端的中心服務器。因此,對該語言有以下幾個要求:
- 客戶端應用程序運行于嵌入式設備之上,要求編譯的二進制文件盡可能地小;
- 能夠與Linux的嵌入式發(fā)行版本Yocto兼容。
- 客戶端要易于安裝,不需要依賴外部項和庫。
- 由于需要在不同的設備上運行,故該語言須具備跨體系結構編譯能力。
- Mender客戶端應用程序運行的設備會是IoT或網絡設備,因此該語言需要具備訪問網絡庫能力。
此外還有一些非功能性要求:
- 此語言能被部門大多數程序員理解掌握;
- 盡可能無難度地實現與現有的C語言編寫的應用程序之間共享和重用已有代碼,客戶端和服務器應用程序之間亦可重用代碼。
- 還要考慮開發(fā)速度——團隊時刻面臨著快速添加新功能的需求和壓力。
Go、C 和 C++的比較如圖 1 所示。Go之所以被選擇,主要是由于它支持緩沖區(qū)溢出保護、自動內存管理、使用標準數據容器,以及對JSON、HTTP和SSL/TLS庫的集成支持。
圖 1:Go、C 和 C++的功能表比較
評估團隊使用Yocto創(chuàng)建一個完善的定制Linux映像,比較了原始的映像體積較之具有網絡堆棧的映像體積,以及最終應用程序寫入映像的方式。在這一評估過程中,Go是可以與C,C++和C++ / Qt相媲美的。由于Go應用程序可以靜態(tài)編譯為單個二進制文件,因此它并不需要任何額外的虛擬環(huán)境(比如Java除了二進制文件之外還需要虛擬機),Go代碼在設備上運行也不需要依賴其他項。
圖 2:Go 與其他編程語言進行比較
比較GO和C
選中Go語言進行開發(fā),還源于它極其豐富的標準庫。這一優(yōu)勢有助于開發(fā)進程的加快,特別是與C語言相比。Go語言從C、C++和Python繼承了許多元素,包括表達式語句,控制流語句,數據結構,接口,指針,引用傳遞概念,參數解析語法,字符串處理和垃圾回收機制。憑借其優(yōu)化的編譯器,Go 可在嵌入式設備上實現代碼本地運行。
當然,Go語言不可避免的會有一些缺點,后面也將提及。但瑕不掩瑜,這并不影響Go語言明顯的優(yōu)勢,比如在開發(fā)速度和語言構建方面的便利性。這些對于評估團隊的選擇也有所影響,下面逐一來看。
Go和C代碼體積比較
在代碼體積方面,Go不如C輕便,這是它為數不多的缺點之一。以最簡單的應用程序“hello world”為例,在Go使用內置printIn函數編寫,去除調試符號后,它的大小為剛剛超過600KB(代碼段1)。如果將fmt包及其依賴項包括在內,則大小將增至 1.5 MB(代碼段 2)。
與之相比較,使用C語言的話,如果是構建一個動態(tài)鏈接庫,則它的大小只有8KB。但如果使用靜態(tài)鏈接庫,則大小將增加到800 KB以上,比較令人意外的是它比Go二進制文件(代碼段3)還要大。
代碼段1:最基本的 Go語言 “hello world” 代碼:
package main
func main() {
println("hello world")
}
$ go build
> 938K
$ go build -ldflags ‘-s -w’
> 682K
$ go build & strip
> 623K
代碼段2:標準的Go語言“hello world” 代碼:
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
$ go build
> 1,5M
代碼段3:C語言“hello world” 代碼:
#include
int main(void)
{
printf("hello world\n");
return 0;
}
$ gcc main.c
> 8,5K
$ ldd a.out
> linux-vdso.so.1
> libc.so.6
> /lib64/ld-linux-x86-64.so.2
$ gcc -static main.c
> 892K
$ gcc -static main.c & strip
> 821K
Go與C的運行速度比較
編譯后的Go代碼運行起來通常會比C語言的可執(zhí)行文件慢。Go是具備完全垃圾收集機制的,生來就影響了運行速度。使用C語言時可以精確地指定為變量分配的內存的位置,可以具體到該變量是在棧上還是在堆上;而使用Go時,編譯器會自動處理將變量分配在何處。程序員可以看到變量的分配位置 (go build -gcflags -m),但不能強制編譯器僅使用摸個位置比如棧。
但是,速度不是僅限于上述,還要考慮到編譯速度和開發(fā)速度。Go提供了極快的編譯速度。比如,15,000行代碼Go客戶端僅需1.4秒就能編譯完畢。并且,Go是為并發(fā)執(zhí)行(goroutines和channels)而設計的,前面闡述過的豐富的標準庫能夠涵蓋大部分基本需求,因此有利于程序員開發(fā)速度加快。
編譯和交叉編譯
有兩種編譯器可供程序員選擇使用:原始編譯器叫做gc ,默認安裝程序自帶,由Google編寫和維護。第二種叫做gccgo,是GCC的前端。gccgo使用起來編譯速度極快,大型模塊通常幾秒鐘就可以編譯完畢。如前所述,Go默認是以靜態(tài)庫編譯,這樣就可以無需額外依賴項或虛擬機創(chuàng)建單個二進制文件??梢允褂?linkshared標志創(chuàng)建和使用共享庫。通常,Go不需要構建文件,如需構建則可通過使用簡單的“go build”命令執(zhí)行,高級復雜的構建可以使用Makefile。這里是在Mender使用的Makefile。
除此之外,Go在交叉編譯方面支持眾多操作系統(tǒng)和架構。圖 3 示例了 Go 支持的各種操作系統(tǒng)和平臺。
圖3 Go 支持的各種操作系統(tǒng)和平臺
在 Go 中調試和測試
許多開發(fā)人員使用GDB監(jiān)視程序執(zhí)行情況。對于高并發(fā)Go應用程序,使用GDB調試時會出現一些問題。萬幸的是,一個名為 Delve 的專用Go調試器是可以完美使用的,確保了即使是只會使用GDB的開發(fā)人員大多數情形下也能輕松調試。
Go代碼中添加測試和單元測試十分簡單,測試是內置在Go語言中的——只需創(chuàng)建一個帶有“test”后綴的文件,為函數添加測試前綴,導入測試包,然后運行“go test”。所有測試就將自動從源中獲取并相應執(zhí)行。
并發(fā)支持
Go語言對并發(fā)支持特別友好。它有兩個內置調度機制:goroutines和channels。goroutines是輕量級線程,僅僅2 kB。創(chuàng)建非常容易:只需要在函數前面添加“go”關鍵字,它就會同時執(zhí)行。Go有自己的內部調度器,可以根據需要將goroutines多路復用到OS線程中。channels是用于在 goroutine 之間交換消息的“管道”,可以是阻塞的,也可以是通行的。
靜態(tài)和動態(tài)庫:Go語言中的的 C 代碼
Go有許多鮮為人知的功能,允許程序員使用特殊標志將指令發(fā)送給編譯器、連接器和工具鏈的其他部分。其中包括-buildmode和-linkshared標志,二者皆可用于為Go和C代碼段創(chuàng)建并使用靜態(tài)和動態(tài)庫。通過特定標志的組合,程序員可以使用生成的C語言頭文件創(chuàng)建靜態(tài)或動態(tài)庫,這些頭文件以后可由C代碼調用。
是的,沒錯!使用Go,可以調用C代碼并擁有兩全其美的功能。Go發(fā)行版包含一個工具名為cgo,可以執(zhí)行C代碼,這使得重用程序員自己的或系統(tǒng)的C庫成為可能。實際上,Cgo以及C系統(tǒng)庫的間接引用是十分常見的。某些情況下,標準C庫例程就是由Go語言構造語法本身從Go實例中選取。
例如,在Unix系統(tǒng)上使用網絡包時,很有可能會選擇基于cgo的解析器。它會調用C庫例程 ( getaddrinfo和 getnameinfo)來解析無法使用本機Go解析器的名稱(例如在 OS X上直接 DNS 調用被禁用時);另一種常見情況則是使用系統(tǒng)/用戶程序包時。如果想跳過構建cgo部件,程序員可以通過osusergo和netgo標記 (go build -tags osusergo,netgo)或使用CGO_ENABLED=0變量完全禁用 cgo。
將C和Go混合在一起時,還需要注意一些比較棘手的事情。由于Go是有垃圾回收機制的而 C不是,所以如果在Go代碼中使用了任何分配在C代碼堆棧上的C變量,都必須在 Go 中聲明釋放。
通過使用接口生成工具(SWIG)來實現,C++也可以在Go代碼中使用。SWIGC能夠將Go與C++以及Python等語言融合在一起。
Go的優(yōu)點大于缺陷
從以往的經驗可以得出Go既有優(yōu)點也有缺陷。就負面因素來講,社區(qū)中有很多外部庫,但良莠不齊,需要非常小心辨別使用。隨著Go語言的成熟和廣泛采用,這種情況正在迅速改善。
此外,當Go代碼中存在一些C綁定時,事情通常會變得更為復雜,尤其是交叉編譯,如果不導入整個C交叉編譯基礎結構,就難以完成。
總體而言,使用Go進行嵌入式開發(fā)還是有很多優(yōu)點的。從C或Python(或二者兼有)過渡到Go并在短期內使用是快速簡單而可行的。Go語言提供了非常優(yōu)秀的工具和一個包含100多個軟件包的標準庫。程序員可以輕松控制和設置運行參數,例如,要使用的操作系統(tǒng)線程數(GOMAXPROCS),打開或關閉垃圾回收 (GOGC=off)等。庫以及代碼可以在服務器和客戶端開發(fā)團隊之間輕松共享,就像文中提及的實例那樣。
這樣說可能會引起爭論,但一致的編碼標準事實上加快了開發(fā)速度。無論程序員要檢查的代碼是什么,它看起來是一致的。無需耗費時間在思考使用哪種編碼標準上。
工程師們開發(fā)了一些嵌入式Go應用程序的演示,可以應用在新興設備上(例如Beaglebone Black或Raspberry Pi):其中一個名為“恒溫器”,基于Beaglebone硬件,使用紅外距離、溫度和濕度傳感器,并可以通過 Web界面讀取所有傳感器讀數;還有一個是基于PRi的機器人汽車,帶有攝像頭,可以通過Web界面進行控制。喜歡就去享受吧!
譯者介紹
張哲剛,社區(qū)編輯,系統(tǒng)運維工程師,國內較早一批硬件評測及互聯(lián)網從業(yè)者,曾入職阿里巴巴。十余年IT項目管理經驗,具備復合知識技能,曾參與多個網站架構設計、電子政務系統(tǒng)開發(fā),主導過某地市級招生考試管理平臺運維工作。
原文標題:??Comparing Go vs. C in embedded applications??,作者:Marcin Pasinski
網站題目:Go與C在嵌入式應用開發(fā)中的對比
文章位置:http://m.5511xx.com/article/cdjehhe.html


咨詢
建站咨詢
