近來在博客上關(guān)于Scala與Erlang之間的爭論越來越熱。未來注定是多核的世界,問題在于如何去解決多核的危機(jī)。Scala和Erlang是兩門渴望成為其解決方案的語言,但它們也有些許的不同。那么它們所采取的方式各有什么利弊呢? 引入問題摩爾定律已經(jīng)改變了。我們不再獲得和以前一樣的時鐘頻率增長,取而代之,我們得到了更多的(CPU)核心。今天,也許你的筆記本都已經(jīng)是雙核的了。 為了利用多核的特性,應(yīng)用程序需要支持并發(fā)。如果你的客戶買了一臺八核的機(jī)器,要向他們解釋清楚正常情況下應(yīng)用程序只會用到12%的CPU能力將是一件費(fèi)時費(fèi)力的事,即便該機(jī)器是為該應(yīng)用量身定制的。 在未來,情況可能變得更糟。你的順序執(zhí)行代碼不僅不會跑得更快,甚至有可能實(shí)際上跑得更慢。其原因在于,你獲得越多的核心,由于功耗和散熱的影響,每個核心就會更慢。幾年之后,英特爾就會給我們帶來32核的CPU,按這種趨勢,在我們不知不覺之中數(shù)千核的CPU就會出現(xiàn)。但每個核心都會比現(xiàn)在的核心慢很多。 并發(fā)代碼一個顯見的解決途徑就是編寫(或重寫)軟件以支持并發(fā)。最常見的方式莫過于使用線程,但大多數(shù)開發(fā)者都認(rèn)為基于線程的應(yīng)用編寫起來特別的困難。死鎖,餓死以及競爭條件對大多數(shù)并發(fā)開發(fā)者來說都是太熟悉的概念了。Erlang和Scala都大大減輕了這種痛苦。 語言概覽Scala常被看作是下一個主要的JVM語言。它結(jié)合了面向?qū)ο缶幊痰姆妒胶秃瘮?shù)式編程的范式,與Java相比有著更簡潔的語法,它是靜態(tài)類型的,有著跟Java一樣或者有時候更快的運(yùn)行速度。有太多的理由值得去認(rèn)真探索一下Scala。 Erlang是一門為健壯性而生的語言,由于它的設(shè)計(jì),它自然又是一門有著極好伸縮性的語言。它比Java歷史更早,但卻常被看作引領(lǐng)未來并發(fā)的語言。它是一門動態(tài)類型的函數(shù)式語言,有著一些非凡的系統(tǒng)正常運(yùn)行時間的成功例子。 爭論核心那么Scala與Erlang爭論的到底是什么呢?說到底,就是性能表現(xiàn)與伸縮能力,但這爭論也包括了其它像風(fēng)格,語言特性以及庫支持等等。這場爭論開始于Ted Neward有一次無心的給出了他對幾種語言的看法,并稱“[Erlang]在其自己解釋器上運(yùn)行事實(shí)上[是]很差的”。 Steve Vinoski與Ted于是展開了幾輪爭論,但這一討論很快轉(zhuǎn)移到了更多的博客上,爭論的焦點(diǎn)也轉(zhuǎn)變成了Scala與Erlang之間那些有趣的差異和共同點(diǎn)。我們將總結(jié)每個有意思的論點(diǎn)并給出每種語言的利弊,并表達(dá)對一些問題的各種不同看法。 可靠性Steve Vinoski就Ted所發(fā)表的帖子進(jìn)行了回應(yīng),給出了他對于“Erlang在其自己解釋器上運(yùn)行”的感受:
Steve談到這個問題,就算一個語言本身可靠,它所依賴的基礎(chǔ)也必須可靠才行。因?yàn)镋rlang從骨子里就是為可靠性而設(shè)計(jì)的,從而支持并發(fā),所以它不會受到一些并發(fā)性常見問題的影響,這主要是底層庫包在并發(fā)環(huán)境下運(yùn)行很好。 另一方面,Scala是站在JVM之上的,所以一個重要賣點(diǎn)在于可潛在地使用所有現(xiàn)成的Java代碼。然而,大部分的Java代碼并非專為并發(fā)而設(shè)計(jì)的,使用Scala代碼時要將此考慮進(jìn)去。 輕量級進(jìn)程要運(yùn)行大規(guī)模并發(fā)應(yīng)用,你需要大量的并行執(zhí)行。這可以通過幾種方式達(dá)到。使用線程是一種常見的方式,使用進(jìn)程又是另一種。其區(qū)別之處在于,線程與其它線程之間共享內(nèi)存,而進(jìn)程是相互獨(dú)立的。這意味著線程需要像互斥信號這樣的鎖機(jī)制,防止兩個線程在同一時間對同一內(nèi)存進(jìn)行操作,但進(jìn)程不會受此問題影響,相反是使用一些消息傳遞機(jī)制來跟其它的進(jìn)程間通信。但進(jìn)程在性能和內(nèi)存方面的代價(jià)是昂貴的,這正是人們就算知道基于線程的并發(fā)是一種極復(fù)雜的編程模型也寧愿選擇它的原因。 Steve Vinoski這樣寫到: 提供互不共享的輕量級進(jìn)程架構(gòu)將使得大規(guī)模并發(fā)能力變得十分容易,但這并不意味著一旦你設(shè)計(jì)好了,剩下的就只是編程的工作那么簡單。 Erlang采取了這樣的并發(fā)方式。一個Erlang進(jìn)程是非常輕量化的,Erlang應(yīng)用常常擁有成千上萬的線程甚至更多。 Scala通過基于事件的Actor從另一方面達(dá)到了同樣的效果。Yariv Sadan解釋說:
Yariv解釋到,盡管如此,這里面也還是有一些區(qū)別的: 與Erlang進(jìn)程的區(qū)別之處在于,每個OS線程內(nèi)部,基于事件的Actor是順序執(zhí)行的并且使用沒有強(qiáng)占式調(diào)度算法。這使得一個基于事件的Actor可能在很長一段時間內(nèi)阻塞其OS線程(甚至是無限的)。 不可變性Erlang是一門函數(shù)式語言。這意味著其數(shù)據(jù)是不可變的,像Java的String一樣,并且沒有副作用帶來的風(fēng)險(xiǎn)。對數(shù)據(jù)的任意操作會產(chǎn)生一個該數(shù)據(jù)新的修改后的版本,但原數(shù)據(jù)仍然不變。在談到健壯性的時候,不可變性是其需要高度注意的一個因素,因?yàn)闆]有代碼可以無意間修改其它代碼依賴的數(shù)據(jù),但從并發(fā)的觀點(diǎn)來看,不可變性也是一個十分重要的特性。如果數(shù)據(jù)不可變,其被兩個并行執(zhí)行路徑更改的風(fēng)險(xiǎn)就不存在,因?yàn)闆]有辦法改變它且不需要保持同步,所以數(shù)據(jù)可以被拷貝到其它機(jī)器上。 因?yàn)镾cala構(gòu)建在JVM之上,結(jié)合了面向?qū)ο蠛秃瘮?shù)式方法的特點(diǎn),它不具備像純函數(shù)式語言的不可變性的保證。然而,在Yariv日志的評論部分,Yariv和David Pollack就這兩門語言之間的差別展開了一場有趣的討論。David,Scala Web框架Lift的作者,給出了他對于不可變性的看法: 不可變性 —— Erlang強(qiáng)制了這一點(diǎn),而且你幾乎無法繞過它。但是,與強(qiáng)制一個單一類型相比,你可以用Scala神奇強(qiáng)大的類型系統(tǒng)的剩余部分去交換。我在進(jìn)行Scala Actor編碼時使用不可變數(shù)據(jù),而讓Scala的類型系統(tǒng)負(fù)責(zé)其它類型。 Yariv問到: 只發(fā)送不可變類型難道不是一個重大限制嗎?這意味著,例如,你不能從Hibernate裝載一個簡單的bean并將它發(fā)送給其它Actor。 David回答到: 我曾基于Scala的Actor構(gòu)建個多個生產(chǎn)系統(tǒng)。實(shí)際上對于不可變性問題并沒有多少工作需要處理。你只需要將你的相關(guān)類(消息)定義為不可變的,其它的就不用管了。 類型系統(tǒng)Erlang是動態(tài)類型的,而Scala是靜態(tài)類型的并且相比Java有著更強(qiáng)的類型系統(tǒng)。然而,與Java相比最大的一個區(qū)別是Scala可以類型推斷。這意味著你可以省掉大部分的類型注解,使得代碼更加干凈而編譯器照樣會做所有的檢查。 關(guān)于動態(tài)與靜態(tài)系統(tǒng)之間孰是孰非的爭論看來永遠(yuǎn)也不會停止,但Erlang和Scala之間卻有著顯而易見的區(qū)別。 尾遞歸或是循環(huán)Yariv又提到: 函數(shù)式編程與遞歸從來都是形影不離的。實(shí)際上離開了尾遞歸你很難寫出有用的Erlang程序,那是因?yàn)镋rlang沒有循環(huán)——它對一切都使用遞歸(這在我看來是一件好事 :))。 這顯然使得Erlang與Scala產(chǎn)生了很大差別。Scala提供了很多更傳統(tǒng)的迭代,但David Pollack并沒看出在這種環(huán)境下尾遞歸有什么優(yōu)勢: 尾遞歸——對基于事件的Actor來說根本不是什么問題。 如此說來,這僅僅有關(guān)你的偏愛和風(fēng)格罷了。 熱交換代碼由于Erlang是為可靠性而生的,熱交換代碼(運(yùn)行時替換代碼)是其內(nèi)建的天性。 JVM對熱交換代碼有所支持。類可以被改變,但由于其靜態(tài)的類型系統(tǒng),其方法簽名是不可改變的——只有其內(nèi)容可以改變。雖然有第三方工具致力于此,也有框架(提倡以一種使運(yùn)行時更方便交換類的編程風(fēng)格書寫代碼),但就算運(yùn)行在JVM上,如何進(jìn)行交換仍是取決于你的Scala Actor是如何構(gòu)建的。Jonas Bonér就此給出了一個詳盡的例子。 總結(jié)Scala和Erlang都是致力于解決多核危機(jī)的語言。它們來自不同的背景和年代,因此對待某些問題的方式也不盡相同,然而在許多方面它們的共識大于分歧,至少在并發(fā)性上如此。 Erlang已經(jīng)有著數(shù)十年的歷史,并且已經(jīng)在許多關(guān)鍵的真實(shí)系統(tǒng)中證明了自己。其不足之處在于它有一點(diǎn)像一個孤島,最近的多語言編程的趨勢似乎對Erlang社區(qū)影響不大。 另一方面,Scala是同一類型應(yīng)用的新生兒。一些真實(shí)應(yīng)用即將誕生,并且一些公司將未來押在了上面。Scala相對Erlang的最大優(yōu)勢在于,它運(yùn)行在JVM之上并且可以利用所有現(xiàn)成Java代碼、框架和許多工具。話雖如此,這種強(qiáng)大的能力也要求了更大的責(zé)任,因?yàn)榇蟛糠諮ava代碼不可能自動適應(yīng)Scala的Actor模型。 對于主流語言無法幫開發(fā)者解決的壓力越來越大的問題,兩種語言都對提供了相似的解決途徑。希望你在讀完這篇爭論總結(jié)之后,能更清楚哪種語言更適合你的特殊要求,并對其深入了解。 未來是多核的。Scala和Erlang將會越來越流行。 查看英文原文:The multicore crises: Scala vs. Erlang |
|