明天的嵌入式系統(tǒng)編程語(yǔ)言仍然是C語(yǔ)言嗎?
摘要:本文介紹了嵌入式系統(tǒng)編程語(yǔ)言的發(fā)展,并將C語(yǔ)言和時(shí)下其他較為流行的編程語(yǔ)言比較,分析了各自的優(yōu)缺點(diǎn)和未來(lái)發(fā)展趨勢(shì)。
本文引用地址:http://m.butianyuan.cn/article/201606/293251.htm您在下一項(xiàng)目編程時(shí)所使用的最佳語(yǔ)言是什么? 如果您是一名嵌入式系統(tǒng)設(shè)計(jì)人員,可能認(rèn)為這一問(wèn)題實(shí)在可笑。您會(huì)使用C語(yǔ)言,如果希望加強(qiáng)管理,則會(huì)使用C衍生的C++??赡軙?huì)有一些關(guān)鍵代碼片段是以匯編語(yǔ)言編寫(xiě)的,但是,據(jù)Barr集團(tuán)最近的一項(xiàng)研究表明,目前95%的嵌入式系統(tǒng)代碼是采用C或者C++編寫(xiě)的。
然而,世界是在變化的。新的程序員、新挑戰(zhàn)以及新體系結(jié)構(gòu)讓C松開(kāi)了在嵌入式軟件上的“抓手”。據(jù)最近的一項(xiàng)研究表明,嵌入式計(jì)算語(yǔ)言發(fā)展最快的是Python,當(dāng)然還有很多其他參與競(jìng)爭(zhēng)的語(yǔ)言,只是這些語(yǔ)言仍然占少數(shù)。但是逐漸地,一直堅(jiān)持使用C/C++的程序員像20年前匯編語(yǔ)言專(zhuān)家那樣開(kāi)始冒險(xiǎn)——采用更快、更緊湊和更可靠的程序。 圖1提出了新語(yǔ)言能夠提高嵌入式計(jì)算機(jī)領(lǐng)域的效能。
C語(yǔ)言在嵌入式領(lǐng)域中的地位受到?jīng)_擊
嵌入式算法變革的一個(gè)主要推動(dòng)力量是其他工作環(huán)境的程序員進(jìn)入了嵌入式領(lǐng)域。這方面最明顯的是剛畢業(yè)的學(xué)生進(jìn)入職場(chǎng)。以前,剛畢業(yè)的學(xué)生在C課程中學(xué)會(huì)了編程,會(huì)用C或者C++完成他們的大部分項(xiàng)目。而現(xiàn)在,已經(jīng)不再如此了。Intel軟件工程經(jīng)理David Stewart注意到,“現(xiàn)在,大部分計(jì)算機(jī)科學(xué)課程使用Python作為他們的入門(mén)語(yǔ)言。”計(jì)算機(jī)科學(xué)專(zhuān)業(yè)畢業(yè)的學(xué)生很有可能在Python、Ruby以及幾種腳本語(yǔ)言上有豐富的經(jīng)驗(yàn),但是他們可能從未認(rèn)真地使用過(guò)C語(yǔ)言。同時(shí),其他影響也越來(lái)越多。使用Android作為平臺(tái)進(jìn)行相關(guān)的或者用戶友好的嵌入式設(shè)計(jì),為Android的自然語(yǔ)言——Java,帶來(lái)了機(jī)會(huì)。在這一復(fù)雜景象的另一端,機(jī)器人、無(wú)人機(jī)或者相似的小項(xiàng)目業(yè)余愛(ài)好開(kāi)發(fā)人員通常都有Arduino或者Raspberry-Pi背景。他們的經(jīng)驗(yàn)會(huì)體現(xiàn)在非常緊湊和簡(jiǎn)單的程序發(fā)生器或者B#等小型語(yǔ)言環(huán)境里。
這一現(xiàn)象對(duì)物聯(lián)網(wǎng)(IoT)的廣泛研究也產(chǎn)生了影響,網(wǎng)絡(luò)開(kāi)發(fā)人員也參與到討論中。他們認(rèn)為,如果嵌入式系統(tǒng)的外部接口是RESTful Web,編程語(yǔ)言應(yīng)該是JavaScript或者其服務(wù)器側(cè)相關(guān)的Node.js。熱衷于使用C語(yǔ)言進(jìn)行開(kāi)發(fā)的人員應(yīng)該觀察一下node.js——貝寶和沃爾瑪?shù)裙驹谄髽I(yè)規(guī)模的開(kāi)發(fā)中大量使用了這一可擴(kuò)展平臺(tái),據(jù)跟蹤調(diào)查網(wǎng)站modulecounts.com,在任何編程語(yǔ)言中,該平臺(tái)的輔助支持系統(tǒng)增長(zhǎng)是最快的。
選擇Node.js的動(dòng)機(jī)部分是源自文化,但是也有體系結(jié)構(gòu)方面的因素。IoT會(huì)在客戶側(cè)、互聯(lián)網(wǎng)以及服務(wù)器側(cè)之間分配其嵌入式系統(tǒng)任務(wù)。其中,客戶側(cè)連接實(shí)際環(huán)境,通常要求盡可能少地采用硬件??蛻魝?cè)很自然地采用硬件專(zhuān)用庫(kù)支持的Web應(yīng)用程序,而服務(wù)器側(cè)則是服務(wù)器應(yīng)用程序。這樣,對(duì)于Web程序員,在IoT系統(tǒng)編程中很顯然會(huì)使用JavaScript和Node.js。
日益復(fù)雜的嵌入式算法是變革的另一推動(dòng)力量。簡(jiǎn)單的控制環(huán)路被卡爾曼濾波器、神經(jīng)網(wǎng)絡(luò)以及基于模型的控制功能所替代,高性能計(jì)算語(yǔ)言——Python,開(kāi)放計(jì)算語(yǔ)言(例如OpenCL?)以及MATLAB等基于模型的環(huán)境逐漸發(fā)展起來(lái)。
強(qiáng)烈的動(dòng)機(jī)
那么這些新人們?yōu)槭裁床混o下心來(lái)學(xué)習(xí)C語(yǔ)言呢? Stewart說(shuō):“真正的原因在于開(kāi)發(fā)人員的效能?!狈磳?duì)C語(yǔ)言的人一直認(rèn)為這種語(yǔ)言編寫(xiě)慢,容易出錯(cuò),會(huì)帶來(lái)意想不到的硬件相關(guān)問(wèn)題,并且除了最初的程序員,其他人很難讀懂它。這些因素會(huì)對(duì)提高設(shè)計(jì)效能產(chǎn)生不利影響。而很多最近出現(xiàn)的語(yǔ)言逐步轉(zhuǎn)向快速學(xué)習(xí)和高效的代碼重用。雖然目前幾乎所有語(yǔ)言都受益于C語(yǔ)言高度簡(jiǎn)潔的語(yǔ)法,但現(xiàn)在的重點(diǎn)已經(jīng)轉(zhuǎn)回可讀性,而不是最少字符數(shù)。不但在現(xiàn)代語(yǔ)言中鼓勵(lì)實(shí)現(xiàn)協(xié)調(diào)一致的文檔,而且結(jié)構(gòu)化約定也通常會(huì)這樣定義文檔。C程序員一直把這類(lèi)文檔看成是自由表述的例子,因?yàn)樽髡咦约翰粫?huì)牽連其中。例如,這些約定使得實(shí)用工具程序能夠從Python組件的結(jié)構(gòu)化注釋中生成用戶手冊(cè)。
現(xiàn)代語(yǔ)言還采用了高級(jí)數(shù)據(jù)結(jié)構(gòu),可以在C++環(huán)境中建立任何對(duì)象,并重用它?;谥羔槪琍ython還提供自然List和Dictionary數(shù)據(jù)類(lèi)型。而Ruby等其他語(yǔ)言,基本上是面向?qū)ο蟮?,支持結(jié)構(gòu)和重用,這使其可以融入到程序員的習(xí)慣中。
影響了現(xiàn)代語(yǔ)言是否易于重用的另外兩個(gè)重要因素是動(dòng)態(tài)輸入和模塊化。動(dòng)態(tài)輸入是一個(gè)很有爭(zhēng)議的因素。當(dāng)程序員在使用變量時(shí),解釋程序確定程序員傳送給表達(dá)式的數(shù)值的當(dāng)前數(shù)據(jù)類(lèi)型——幾乎所有這些服務(wù)器側(cè)語(yǔ)言都是解釋性的,而不是編譯的。然后,解釋程序會(huì)選擇相應(yīng)的操作,評(píng)估含有該數(shù)據(jù)類(lèi)型的表達(dá)式。這樣,程序員不用太過(guò)擔(dān)心他要調(diào)用的函數(shù)需要的是整數(shù)變量還是實(shí)數(shù)變量。但是,嵌入式程序和代碼可靠性專(zhuān)家很快指出,動(dòng)態(tài)輸入在運(yùn)行時(shí)實(shí)際上效率不高。另一個(gè)因素是部分程序員對(duì)模塊化的偏見(jiàn)。有時(shí)候會(huì)有人說(shuō),Python編程實(shí)際上不是編程,而是腳本,是把別人用C語(yǔ)言編寫(xiě)的函數(shù)調(diào)用或串起來(lái)。
可讀性、協(xié)調(diào)一致的文檔、動(dòng)態(tài)輸入以及函數(shù)大量的重用等,催化了開(kāi)源領(lǐng)域中輔助支持系統(tǒng)的爆發(fā)。程序員本能地會(huì)在巨大的開(kāi)源庫(kù)中找到他們能夠使用的函數(shù),例如,npm (用于Node.js)、PyPI (用于Python)或者Rubygems.org (用于Ruby)。如果他們不用修改組件或者編寫(xiě)新的組件,他們會(huì)回到庫(kù)中工作。結(jié)果,庫(kù)會(huì)越來(lái)越大(npm目前大概有25萬(wàn)個(gè)組件)。這些大規(guī)模的輔助支持系統(tǒng)也相應(yīng)地大幅度提高了程序員的效能。
嵌入式的新編程語(yǔ)言的不足之處及解決方法
這些編程語(yǔ)言盡管有這么多的優(yōu)點(diǎn),但也有缺點(diǎn)。要想在嵌入式計(jì)算領(lǐng)域占據(jù)一席之地還有很多不足。
大部分這些語(yǔ)言最明顯的問(wèn)題是,它們是解釋性的,而不是編譯的。這意味著它們需要可觀的運(yùn)行時(shí)程序包,包括解釋程序本身、工作存儲(chǔ)、動(dòng)態(tài)輸入開(kāi)銷(xiāo)和運(yùn)行時(shí)庫(kù)等,都要適配到嵌入式系統(tǒng)中。基本上,所有這些會(huì)非常緊湊,某些Java虛擬機(jī)可以裝入到幾十K字節(jié)中,但是Node.js、Python以及來(lái)自服務(wù)器側(cè)相似的語(yǔ)言需要自己的空間。一個(gè)兼容性還可以的Python虛擬機(jī)在加入程序員自己的代碼之前可能已經(jīng)占用了幾兆字節(jié)。
在性能問(wèn)題方面,解釋程序讀取每一行代碼(源程序或者預(yù)處理過(guò)的中間級(jí)代碼)需要解析它、進(jìn)行運(yùn)行時(shí)檢查以及調(diào)用執(zhí)行所需操作的例程。在C語(yǔ)言中,這會(huì)導(dǎo)致一行代碼有很多操作,編譯成很多機(jī)器語(yǔ)言指令。執(zhí)行時(shí)間和能耗的成本都會(huì)增加。
在運(yùn)行時(shí)效率方面,可以使用即時(shí)(JiT)編譯器進(jìn)行改進(jìn)。一個(gè)JiT編譯器可以與解釋程序并行工作,為循環(huán)中的代碼生成編譯后的機(jī)器指令,因此,后續(xù)的代碼能夠更快地執(zhí)行。Stewart說(shuō):“JiT技術(shù)非常有趣,PyPy JiT編譯器把Python執(zhí)行速度提高了兩倍?!睂?duì)于效率方面,還研究了其他方法。例如,如果函數(shù)是無(wú)阻塞的,或者使用了信令機(jī)制,有很多函數(shù)調(diào)用的程序即使是在采用循環(huán)展開(kāi)等方法來(lái)建立更多的線程之前,也可以含有很多線程。因此,可以在一個(gè)組件上應(yīng)用很多多線程內(nèi)核——這是高性能計(jì)算已經(jīng)研究應(yīng)用的方向。更進(jìn)一步,Ruby語(yǔ)言本身支持多線程,因此,即使底層操作系統(tǒng)不支持線程,它也能夠產(chǎn)生線程代碼。某些團(tuán)隊(duì)則尋求在硬件加速器中實(shí)現(xiàn)庫(kù)或者組件,例如,圖形處理單元(GPU)、Xeon Phi和FPGA。實(shí)際上,解釋程序本身就會(huì)有適合加速的任務(wù)。
服務(wù)器側(cè)語(yǔ)言遇到的其他困難是缺少處理實(shí)際環(huán)境的結(jié)構(gòu)。在服務(wù)器環(huán)境中,除了網(wǎng)絡(luò)和存儲(chǔ),沒(méi)有實(shí)時(shí)限制,也沒(méi)有I/O。可以通過(guò)幾種方式來(lái)解決這一問(wèn)題。
最簡(jiǎn)單的是,Android環(huán)境以硬件幾乎無(wú)關(guān)的抽象方式包封Java代碼:具有圖形、觸摸屏、音頻、視頻、多個(gè)網(wǎng)絡(luò)以及物理傳感器的虛擬機(jī)。對(duì)于更強(qiáng)調(diào)物理I/O,甚至能夠在微控制器上運(yùn)行的輕型平臺(tái),提供嵌入式Java。
Python等語(yǔ)言需要不同的方法。由于CPython解釋程序運(yùn)行在Linux上,因此,原理上能夠運(yùn)行在有足夠速度和物理存儲(chǔ)器的任何嵌入式Linux系統(tǒng)中。在這方面已經(jīng)有了工作基礎(chǔ),通過(guò)減小裝入時(shí)間開(kāi)銷(xiāo),為物理I/O訪問(wèn)提供功能,使用硬件加速器,進(jìn)一步適應(yīng)CPython,運(yùn)行時(shí)系統(tǒng)適應(yīng)實(shí)時(shí)約束。最新的一個(gè)實(shí)例是STM32微控制器的裸金屬M(fèi)icro Python環(huán)境。雖然這看起來(lái)幾乎不可能,但是已經(jīng)在Node.js下面的JavaScript引擎上有了類(lèi)似的工作。
安全呈現(xiàn)出更多的問(wèn)題。很多安全和可靠性標(biāo)準(zhǔn)不鼓勵(lì)甚至禁止使用未經(jīng)正式認(rèn)證或者全面測(cè)試的開(kāi)源代碼。這些限制使得不可能重用組件,或者重用組件過(guò)于復(fù)雜,對(duì)效能的提高不大。同樣等級(jí)的詳細(xì)檢查也延伸到虛擬機(jī)等開(kāi)源環(huán)境中。在可靠和安全大環(huán)境下,CPython等開(kāi)源平臺(tái)很容易受到攻擊。
未來(lái)的編程語(yǔ)言發(fā)展方向
最后,考慮到有眾多的推動(dòng)力量促使新語(yǔ)言進(jìn)入嵌入式世界中,可以預(yù)見(jiàn)到會(huì)有多語(yǔ)系統(tǒng),這種系統(tǒng)含有的組件來(lái)自多種源語(yǔ)言,每一種選擇要使用的關(guān)鍵庫(kù),或者方便某類(lèi)開(kāi)發(fā)人員使用。當(dāng)然,您可以在不同的CPU內(nèi)核上放置幾種虛擬機(jī),在一個(gè)內(nèi)核管理程序下相統(tǒng)一,然后,通過(guò)函數(shù)調(diào)用,為任務(wù)間消息的傳送提供約定。但是,這樣的系統(tǒng)最終會(huì)非常大。
另一種可能是一組語(yǔ)言相關(guān)解釋程序,為JiT編譯器生成公共中間代碼(圖2)。當(dāng)然,還能列出其他問(wèn)題,例如,不同的任務(wù)間具有不同的通信模型、存儲(chǔ)器模型和調(diào)試環(huán)境,但這些問(wèn)題總是能夠解決的。
小結(jié)
如果這些最終會(huì)到來(lái),那么,一名經(jīng)驗(yàn)豐富的嵌入式程序員該如何應(yīng)對(duì)? 您可以從Web編程、服務(wù)器甚至業(yè)余愛(ài)好者使用的開(kāi)發(fā)環(huán)境中研究這些語(yǔ)言。您可以在下一項(xiàng)目中,嘗試在C++和解析語(yǔ)言中開(kāi)發(fā)組件。這需要時(shí)間學(xué)習(xí),但是獨(dú)立并行開(kāi)發(fā)是值得的。
本文來(lái)源于中國(guó)科技期刊《電子產(chǎn)品世界》2016年第6期第18頁(yè),歡迎您寫(xiě)論文時(shí)引用,并注明出處。
評(píng)論