編程語(yǔ)言的發(fā)展趨勢及未來(lái)方向(4):動(dòng)態(tài)語(yǔ)言
這是Anders Hejlsberg(不用介紹這是誰(shuí)了吧)在比利時(shí)TechDays 2010所做的開(kāi)場(chǎng)演講。由于最近我在博客上關(guān)于語(yǔ)言的討論比較多,出于應景,也打算將Anders的演講完整地聽(tīng)寫(xiě)出來(lái)。在上一部分中,Anders談及了聲明式編程的另一個(gè)重要組成部分:函數式編程,并使用.NET平臺上的函數式編程語(yǔ)言F#進(jìn)行了演示。在這一部分中,Anders討論了動(dòng)態(tài)語(yǔ)言及JavaScript的相關(guān)內容,“動(dòng)態(tài)性”也是Anders眼中編程語(yǔ)言的發(fā)展趨勢之一。
本文引用地址:http://dyxdggzs.com/article/201704/346374.htm如果沒(méi)有特別說(shuō)明,所有的文字都直接翻譯自Anders的演講,并使用我自己的口語(yǔ)習慣表達出來(lái),對于A(yíng)nders的口誤及反復等情況,必要時(shí)在譯文中自然也會(huì )進(jìn)行忽略。為了方便理解,我也會(huì )將視頻中關(guān)鍵部分進(jìn)行截圖,而某些代碼演示則會(huì )直接作為文章內容發(fā)表。
(聽(tīng)寫(xiě)開(kāi)始,接上篇)

我下面繼續要講的是動(dòng)態(tài)語(yǔ)言,這也是我之前提到的三種趨勢之一。

我還是嘗試著(zhù)去找到動(dòng)態(tài)語(yǔ)言的定義,但是你也知道……一般地說(shuō),動(dòng)態(tài)語(yǔ)言是一些不對編譯時(shí)和運行時(shí)進(jìn)行嚴格區分的語(yǔ)言。這不像一些靜態(tài)編程語(yǔ)言,比如C#,你先進(jìn)行編譯,然后會(huì )得到一些編譯期錯誤,稍后再執行,而對于動(dòng)態(tài)語(yǔ)言來(lái)說(shuō)這兩個(gè)階段便混合在一起了。我們都熟悉一些動(dòng)態(tài)語(yǔ)言,比如JavaScript,Python,Ruby,LISP等等。

動(dòng)態(tài)語(yǔ)言有一些優(yōu)勢,而靜態(tài)語(yǔ)言也有著(zhù)另一些優(yōu)勢,這也是兩個(gè)陣營(yíng)爭論多年的內容。老實(shí)講,我認為結果不是兩者中的任意一個(gè),它們都有各自十分重要的優(yōu)點(diǎn),而長(cháng)期來(lái)看,我認為結果應該是兩者的雜交產(chǎn)物,我認為在語(yǔ)言發(fā)展中也可以看到這樣的趨勢,這兩部分內容正在合并。

許多人認定動(dòng)態(tài)語(yǔ)言執行起來(lái)很慢,也沒(méi)有類(lèi)型安全等等。我想在這里觀(guān)察并比較一下,究竟是什么原因會(huì )讓靜態(tài)語(yǔ)言和動(dòng)態(tài)語(yǔ)言在這方面有不同的性質(zhì)。這里有一段有趣的代碼,它的語(yǔ)法在JavaScript和C#里都是正確的,這樣我們便能比較兩種語(yǔ)言是如何處理這段代碼的。

首先我們把它看作是一段C#代碼,它只是用for循環(huán)把一堆整數相加,你肯定不會(huì )這么做,這只是一個(gè)示例。在C#中,當我們使用var關(guān)鍵字時(shí),它表示“請為我推斷這里的類(lèi)型”,所以在這里a和i的類(lèi)型都是int。

這斷代碼在執行的時(shí)候,這兩個(gè)值都是32位整數,而for循環(huán)只是簡(jiǎn)單的使用ADD指令即可,執行起來(lái)自然效率很高。

但如果從JavaScript或是動(dòng)態(tài)語(yǔ)言的角度來(lái)看……或者說(shuō)對于動(dòng)態(tài)類(lèi)型的語(yǔ)言來(lái)說(shuō),var只代表了“一個(gè)值”,它可以是任意類(lèi)型,我們不知道它究竟是什么。所以當我們使用var a或var i時(shí),我們只是定義了兩個(gè)值,其中包含了一個(gè)“類(lèi)型”標記,表明在運行時(shí)它是個(gè)什么類(lèi)型。在這里它是一個(gè)int,因此包含了存儲int值的空間。但有些時(shí)候,例如要存儲一個(gè)double值,那么可能便需要更多的空間,還可能是一個(gè)字符串,于是便包含一個(gè)引用。
所以?xún)烧叩膮^別之一便是,表示同樣的值在動(dòng)態(tài)語(yǔ)言中會(huì )有一些額外的開(kāi)銷(xiāo),代價(jià)較高。而在如今的CPU中,“空間”便等于“速度”,所以較大的值便需要較長(cháng)時(shí)間進(jìn)行處理,這里便損失了一部分效率。

在JavaScript中,我們如果要處理a加i,那么便不僅僅是一個(gè)ADD指令。首先它必須查看兩個(gè)變量中的類(lèi)型標記,然后根據類(lèi)型選擇合適的相加操作。于是再去加載兩個(gè)值,然后再進(jìn)行加法操作。這里還需要進(jìn)行越界檢查,因為在JavaScript中一旦越界了便要使用double,等等。很明顯在這里也有許多開(kāi)銷(xiāo)。一般來(lái)說(shuō),動(dòng)態(tài)語(yǔ)言是使用解釋器來(lái)執行的,因此還有一些解釋器需要的二進(jìn)制碼。你把這些開(kāi)銷(xiāo)全部加起來(lái)以后,便會(huì )發(fā)現執行代碼時(shí)需要10倍到100倍的開(kāi)銷(xiāo)。

不過(guò)由于近幾年來(lái)出現的一些動(dòng)態(tài)虛擬機或引擎,目前這些情況改善了許多。比方說(shuō),這是傳統的情況(上圖左),如在IE 6或IE 7里使用的非常緩慢的解釋器。目前的情況是,大部分的JavaScript引擎使用了JIT編譯器(上圖中),于是便省下了解釋器的開(kāi)銷(xiāo),這樣性能損失便會(huì )減小至3到10倍。而在過(guò)去的兩三年間,JIT編譯器也變得越來(lái)越高效,瀏覽器中新一代的適應性JIT編譯器(上圖右),如TraceMonkey,V8,還有如今微軟在IE 9中使用的Chakra引擎。這種適應性的JIT編譯器使用了一部分有趣的技術(shù),如Inline Caching、Type Specialization、Hidden Classes、Tracing等等,它們可以將開(kāi)銷(xiāo)降低至2到3倍的范圍內,這種效率的提升可謂十分神奇。
在我看來(lái),JavaScript引擎可能已經(jīng)接近了性能優(yōu)化的極限,我們在效率上可以提升的空間已經(jīng)不多。不過(guò)我同樣認為,如今JavaScript語(yǔ)言的性能已經(jīng)足夠快了,完全有能力統治Web客戶(hù)端。
有人認為,JavaScript從來(lái)不是一種適合進(jìn)行大規模編程的語(yǔ)言。如今也有一些有趣的工具,如Google Web Tookit,在微軟Nikhil Kothari也創(chuàng )建了Script#,讓你可以編寫(xiě)C#或Java代碼,然后將代碼編譯成JavaScript,這就像是將JavaScript當作是一種中間語(yǔ)言。Google Wave的所有代碼都用GWT寫(xiě)成,它的團隊堅持認為用JavaScript不可能完成這樣的工作,因為復雜度實(shí)在太高了。如今在這方面還有一些有趣的開(kāi)發(fā)成果,我不清楚什么時(shí)候會(huì )結束。不過(guò)我認為,這些都不算是大規模的JavaScript開(kāi)發(fā)方案,而編寫(xiě)C#或Java代碼再生成JavaScript的方式也不能算是完全正確的做法。我們可以關(guān)注這方面的走向。

在.NET 4.0的運行時(shí)進(jìn)行動(dòng)態(tài)編程時(shí),我們引入了一個(gè)新功能:動(dòng)態(tài)語(yǔ)言運行時(shí)??梢赃@樣理解,CLR的目的是為靜態(tài)類(lèi)型的編程語(yǔ)言提供一個(gè)統一的框架或編程模型,而DLR便是在.NET平臺上為動(dòng)態(tài)語(yǔ)言提供了統一的編程模型。CLR本身已經(jīng)有一些支持動(dòng)態(tài)編程能力,如反射,Emit等等。不過(guò)在.NET上實(shí)現動(dòng)態(tài)語(yǔ)言的時(shí)候,總會(huì )一遍又一遍地去實(shí)現某些功能,還有如動(dòng)態(tài)語(yǔ)言如何與靜態(tài)語(yǔ)言進(jìn)行交互,這些都由DLR來(lái)提供。DLR的特性包含了,如表達式樹(shù)、動(dòng)態(tài)分發(fā)、Call Site緩存,這可以提高動(dòng)態(tài)代碼的執行效率。
在.NET 4.0中我們使用了DLR,不僅僅是IronPython和IronRuby,還有C# 4和VB.NET 10,它們使用DLR實(shí)現動(dòng)態(tài)分發(fā)功能。因此我們共享了語(yǔ)言的動(dòng)態(tài)能力實(shí)現方式,于是這些語(yǔ)言之間可以輕松地進(jìn)行交互。同樣我們可以與其他多樣性的技術(shù)進(jìn)行交互,例如使用JavaScript操作Silverlight的DOM,或是與Ruby、Python代碼溝通,甚至用來(lái)控制Office等自動(dòng)化服務(wù)。
評論