Erlang是什么?
Erlang編程語(yǔ)言最初目的是進(jìn)行大型電信交換設(shè)備的軟件開(kāi)發(fā),是一種適用于大規(guī)模并行處理環(huán)境的高可靠性編程語(yǔ)言。隨著多核處理器技術(shù)的日漸普及,以及互聯(lián)網(wǎng)、云計(jì)算等技術(shù)的發(fā)展,該語(yǔ)言的應(yīng)用范圍也有逐漸擴(kuò)大之勢(shì)。
每一門(mén)編程語(yǔ)言的推出都是有目標(biāo)的。大多數(shù)的目標(biāo)是為了:提升性能,提升開(kāi)發(fā)者表現(xiàn)力,提升開(kāi)發(fā)者生產(chǎn)力,如Haskell,Python,Go等都是以這三點(diǎn)為主要設(shè)計(jì)核心的。
Erlang的推出則是為了打造一款高并發(fā)高擴(kuò)展性的實(shí)時(shí)系統(tǒng)。例如應(yīng)用于電信,銀行,商業(yè),即時(shí)通訊等場(chǎng)合。Erlang的運(yùn)行時(shí)系統(tǒng)內(nèi)置了對(duì)并發(fā),分布式,容錯(cuò)等的處理。可見(jiàn)與其它以速度,簡(jiǎn)潔,表達(dá)性見(jiàn)長(zhǎng)的語(yǔ)言相比,Erlang無(wú)疑就是只默默無(wú)聞的丑小鴨。
Erlang的容錯(cuò)能力是它與生俱來(lái)的的能力,因?yàn)檫@是電信領(lǐng)域的重要需求。但是這并不代表Erlang是復(fù)雜的、不具表達(dá)力的。
語(yǔ)法
Erlang的語(yǔ)法是很簡(jiǎn)單的,總共只有550行代碼。因此盡管erlang語(yǔ)法與主流語(yǔ)言比有所不同,但是掌握起來(lái)也是很輕松地。連貫性是它的亮點(diǎn),請(qǐng)看如下代碼:
?
我們?cè)趀rlang shell中執(zhí)行它
?
再來(lái)看一個(gè)復(fù)雜一點(diǎn)的代碼:
?
這個(gè)例子里使用了模式匹配功能,稍后再詳細(xì)講。現(xiàn)在嘗試調(diào)用fac函數(shù):
?
怎么樣?它的語(yǔ)法不復(fù)雜吧,我想只有Lisps可與之媲美簡(jiǎn)單性。
表達(dá)性
當(dāng)說(shuō)到Erlang表達(dá)性的時(shí)候,第一時(shí)間想到的可能是消息傳遞,過(guò)程創(chuàng)建和管理。然而這里的重點(diǎn)是模式匹配,特別是接收消息后,模式匹配可使其處理變得非常簡(jiǎn)便。請(qǐng)相當(dāng)這個(gè)以下這個(gè)模式匹配的例子:
?
首先,我們想訪問(wèn)Body和Headers變量。Shell提示的非常清楚:變量是非約束的。接下來(lái)嘗試做更有趣的。
復(fù)制之前的代碼后,接下來(lái)我們將會(huì)使用到http庫(kù)(ibrowse):
?
然后執(zhí)行shell
?
回到之前的代碼里,
?
這里從ibrowse里調(diào)用了send_req函數(shù)。第一個(gè)參數(shù)是URL。第二場(chǎng)數(shù)是headers列表,即我們想發(fā)送的請(qǐng)求。在這里我們沒(méi)有發(fā)送任何的header。最后,第三個(gè)參數(shù)是我們指定的請(qǐng)求動(dòng)作。
接下來(lái)看看其執(zhí)行結(jié)果:
?
其輸出是包含4個(gè)元素的數(shù)組,{Term1,…,TermN}。Erlang數(shù)組與Python數(shù)組是很相似的。第一個(gè)元素是“ok”信息,說(shuō)明程序執(zhí)行正常。第二個(gè)元素是302,HTTP狀態(tài)碼302表示用戶被重定向。第三個(gè)元素是google返回給我們的headers結(jié)果。
?
接下來(lái)嘗試存儲(chǔ)該結(jié)果:
?
其運(yùn)作過(guò)程是:我們發(fā)送了一個(gè)請(qǐng)求給google,然后google對(duì)此進(jìn)行響應(yīng)并返回結(jié)果。ok是一個(gè)原子,302是一個(gè)字符串。他們都沒(méi)有被指派,因?yàn)樗麄儾皇亲兞?。但為什么這里使用了“=”號(hào)?原因在于Erlang中“=”號(hào)是作用不是指派。由于Erlang支持模式匹配機(jī)制,“=”在這里會(huì)作為匹配符來(lái)使用。它會(huì)嘗試尋找“=”號(hào)左右兩部分的共同點(diǎn),然后把值與非約束變量進(jìn)行綁定,因此最后會(huì)把值指派到正確的變量。
所以從ibrowse得到的結(jié)果是:send_req,Erlang會(huì)認(rèn)為我們得到了一個(gè)以元素ok和302為開(kāi)頭的一個(gè)四元數(shù)組。然后因?yàn)镠eaders和Body是非約束的,所以把Google返回的對(duì)應(yīng)內(nèi)容進(jìn)行指派。
?
也就是說(shuō),模式匹配是與它語(yǔ)言的switch或if/else/elif有著異曲同工之妙。
過(guò)程和消息
在函數(shù)式編程里函數(shù)的地位是舉足輕重的。他們可以被指派到變量,或是作為參數(shù)傳給其它函數(shù)或從其它函數(shù)里作為返回值返回。不妨把函數(shù)看作是其它類型。
?
在Erlang創(chuàng)建一個(gè)過(guò)程是很簡(jiǎn)單的,這里使用了內(nèi)置的spawn函數(shù)進(jìn)行過(guò)程創(chuàng)建。
?
Spawn的作用是創(chuàng)建新過(guò)程并返回PID過(guò)程標(biāo)識(shí)。
?
如果你想針對(duì)消息進(jìn)行處理,而不僅僅局限于在shell中檢視結(jié)果,可以進(jìn)行如下處理:
?
這里創(chuàng)建了一個(gè)Echofun函數(shù),作用是接收消息并顯示。
?
Erlang 適合做什么?
問(wèn)題應(yīng)該是Erlang不適合做什么,而不是Erlang可以做什么。都是圖靈完整的語(yǔ)言,理論上你什么都能做,但是大多數(shù)人不會(huì)去拿Erlang開(kāi)發(fā)操作系統(tǒng),因?yàn)樗贿m合做這個(gè)。
那么,Erlang不適合做什么?
首先,數(shù)值計(jì)算。
Erlang是解釋型的,雖然現(xiàn)在的解釋器能夠編譯代碼,但是還是太慢。有些量化的軟件用Fortran寫(xiě)的都需要算好久,換用Erlang會(huì)讓人等得想死。
再一個(gè),業(yè)務(wù)邏輯非常復(fù)雜的系統(tǒng)。
這個(gè)說(shuō)實(shí)話,Erlang真的不適合。Erlang最大的優(yōu)勢(shì)在于并發(fā),以及并發(fā)系統(tǒng)的穩(wěn)定性。這就是為什么很多電信系統(tǒng)后端在使用Erlang。業(yè)務(wù)邏輯復(fù)雜之后,系統(tǒng)設(shè)計(jì)時(shí)分離并發(fā)模塊的時(shí)候就很難了,甚至有時(shí)候是為了并發(fā)而并發(fā),這就沒(méi)有意義了。
Erlang特別適合做io bound的高并發(fā)服務(wù)器。Erlang最大的優(yōu)點(diǎn)就是輕量的線程,有極小的上下文交換(context switch)開(kāi)銷。比如如下的一段代碼秒開(kāi)100000個(gè)線程
[spawn(fun() -> 0 end) || _ <- lists:seq(1, 100000)]。
鑒于這個(gè)特性Erlang很適合做服務(wù)器。有一些很好的框架比如Cowboy性能非常不錯(cuò)。
Eric Moritz - Websocket Demo Results V2
現(xiàn)在越來(lái)越多的公司后端都開(kāi)始嘗試使用Erlang,它還有其他一些優(yōu)勢(shì)。
對(duì)RPC良好的支持,提供了簡(jiǎn)單高效的OTP框架幫助開(kāi)發(fā)者快速實(shí)現(xiàn)功能
無(wú)間斷部署,運(yùn)行時(shí)支持代碼交換。在Shell里一句make:all([load])無(wú)需重啟服務(wù)就更新代碼
在EC2和其他集群里簡(jiǎn)單的部署
垃圾回收
酷炫的語(yǔ)法 - 一行怒解析tcp包
<<4:4, 5:4, ToS:8, ToL:16, Id:16, Flags:3, FlagOffset:13, TTL:8, 6:8, Checksum:16, SrcIP:32, DstIP:32, Payload/binary>> = X.
Erlang像任何其他一門(mén)語(yǔ)言一樣,當(dāng)然是什么都可以做。不過(guò)它更適合做邏輯比較簡(jiǎn)單的服務(wù)端啦。
Erlang與Golang比較
我們都知道,無(wú)論是Python還是Ruby,甚至Java, 都是在解決業(yè)務(wù)層的問(wèn)題,屬于應(yīng)用型語(yǔ)言,以解決業(yè)務(wù)邏輯為主,但還有一個(gè)領(lǐng)域是系統(tǒng)領(lǐng)域,偏網(wǎng)絡(luò)層和底層操作,在這一塊我一直在尋找一種優(yōu)雅的方案,C++被我首先給淘汰掉了,C的開(kāi)發(fā)效率太低,Java倒是比較合適,就是太臃腫,而且缺少系統(tǒng)編程的基因,竟它是企業(yè)級(jí)開(kāi)發(fā)出身的。
Erlang, 它在網(wǎng)絡(luò)層方面表現(xiàn)優(yōu)秀,同時(shí)容錯(cuò)性和健壯性都很不錯(cuò),它的虛擬機(jī)是唯一可以跟JVM媲美的,而且還有OTP的超重量級(jí)武器,幾乎可以是通殺網(wǎng)絡(luò)層應(yīng)用,但根據(jù)我的總結(jié)它有一個(gè)硬傷和一個(gè)軟肋,這一點(diǎn)后面展開(kāi),可以說(shuō)選擇Erlang是我目前所知道的方案里面是最優(yōu)的。
Golang其實(shí)也蠻早的,大概08年的時(shí)候就知道Google在搞一門(mén)奇怪的語(yǔ)言,之后的幾年一直有不少以老莫為代表的人在嘀咕Golang,其實(shí)我一直沒(méi)太關(guān)注,我從ROR中吸取的經(jīng)驗(yàn)是,成熟度對(duì)于商用很重要,后來(lái)基于Golang開(kāi)發(fā)的產(chǎn)品越來(lái)越多,讓我不得不去研究一下, 這我才知道,這就是我夢(mèng)想中的Python,效率和性能達(dá)到了最佳的平衡,對(duì)Go了解越多, 就越不愿意用Erlang寫(xiě)代碼,主要原因:
1、Erlang的硬傷在于代碼的可讀性、表現(xiàn)力,讓我來(lái)舉個(gè)小例子,比如你為你的系統(tǒng)軟件構(gòu)建一個(gè)RESTFUL的接口,我們大致了解一下代碼風(fēng)格, 用Erlang: https://github.com/extend/cowboy/tree/master/examples 用Go:http://code.google.com/p/goweb/wiki/GetStarted,先不說(shuō)Erlang, 無(wú)論是你c/c++/python/ruby/java 出身, 對(duì)Go是不是有種很久違的感覺(jué), 為什么說(shuō)是硬傷? 因?yàn)閷?duì)一門(mén)語(yǔ)言來(lái)說(shuō),語(yǔ)法是不大可能會(huì)大幅度變更的, 而且不會(huì)出現(xiàn)大的變化, 我不知道有沒(méi)有人讀過(guò)《松本行弘的編程世界>,里面闡述的道理很明白, 真正好的編程方式是人去主宰計(jì)算機(jī)而不是計(jì)算機(jī)主宰人, 我感覺(jué)Erlang就有點(diǎn)主宰我的編程思維的感覺(jué)(我的視力本身就不好,它還在不斷的扼殺我的眼睛!), 編程首先是門(mén)邏輯學(xué),其次是工程學(xué),最后才是數(shù)學(xué), 又讓我想起吳軍的《數(shù)學(xué)之美>所說(shuō)的, 人工智能上個(gè)世紀(jì)一直在走彎路, 期望機(jī)器的高度圖靈完備, 而忽視人類本身已有的文明,統(tǒng)計(jì)歸納的應(yīng)用。
2、Erlang的軟肋在于高質(zhì)量的庫(kù)少,盡管有不少殺手級(jí)應(yīng)用, 同樣Go在這方面也是軟肋, 這一點(diǎn)對(duì)于一個(gè)不到五年的語(yǔ)言有情可原, 但對(duì)于一個(gè)20多年的語(yǔ)言是不是有點(diǎn)說(shuō)不過(guò)去, 比如你用json解析庫(kù),很多人都是從mochiweb這個(gè)基本不更新的庫(kù)中去抽取, 而我認(rèn)為對(duì)于類似json這種東西可以考慮融入到語(yǔ)言標(biāo)準(zhǔn)庫(kù)中, 因?yàn)槲磥?lái)的商業(yè)軟件的api化趨勢(shì)越來(lái)越明顯,說(shuō)的難聽(tīng)點(diǎn) , 一個(gè)倚老賣老一個(gè)與時(shí)俱進(jìn),反正我對(duì)Golang的庫(kù)一點(diǎn)也不擔(dān)心, 目前的成績(jī)易經(jīng)非常棒了, 遠(yuǎn)遠(yuǎn)優(yōu)于Ruby/Python的前五年。
? ? ? ?3、Erlang不合群,這主要體現(xiàn)在跟其他語(yǔ)言的交互性上, 當(dāng)然這也有深層次的原因,Erlang本身有自己的哲學(xué) 如出錯(cuò)恢復(fù)機(jī)制, 你融入一個(gè)其他語(yǔ)言的東西進(jìn)去,這帳就不好算,就好比你硬要讓一個(gè)喝咖啡的跟一個(gè)吃大蒜的坐在一起,總之你寫(xiě)一個(gè)Erlang的port遠(yuǎn)遠(yuǎn)比Go復(fù)雜, 甚至比Python/Java還要復(fù)雜,這就造成了Erlang在底層編程上效果不是很好, 沒(méi)法利用linux已有的很多優(yōu)秀成果,我一直認(rèn)為Erlang的什么的mysql/pg/oracle驅(qū)動(dòng)都沒(méi)有必要存在,Erlang一定是一個(gè)self-container應(yīng)用,你只要用到了其他東西, 根據(jù)木桶理論,你就不敢號(hào)稱9個(gè)9,以系統(tǒng)的眼光看問(wèn)題,我覺(jué)得一個(gè)系統(tǒng)的魯棒性不能依賴于某一組件, 這也是為什么愛(ài)立信本身的Erlang應(yīng)用并不廣泛。
4、說(shuō)說(shuō)數(shù)據(jù)類型吧, 我不止聽(tīng)到1個(gè)人說(shuō)Erlang對(duì)字符串的處理不有好, 它把string當(dāng)做list來(lái)處理,其實(shí)本質(zhì)上是該這么,但,還是那句話, 違背了面向人的哲學(xué), 應(yīng)該做一些DSL,比如Golang里面的 := 就是一個(gè)糖衣, 等價(jià)于 var xx yyy = zzzz, 大大方便的程序員少敲不少字符, Golang里面對(duì)字符轉(zhuǎn)可以說(shuō)基本和python差不多,slice map函數(shù)很強(qiáng)大, 支持lambda條件,雖然Erlang的基本類型很少,但有很多構(gòu)造,所謂構(gòu)造等價(jià)于Golang里面復(fù)雜的struct, 也奇怪了,我就是感覺(jué)Erlang構(gòu)造傷眼睛好嗎?可能是各種括號(hào)的比對(duì)的原因吧, 而且我認(rèn)為這是不必要的, 顯然Erlang缺少DSL的基因, 當(dāng)然跟Erlang出身的年代有關(guān), 我不夸張的說(shuō),自打用Erlang以后我的視力又下降了100度左右, 我不是很喜歡lisp所說(shuō)的符號(hào)也是一種語(yǔ)法, 可能這又跟函數(shù)式編程有關(guān)吧:形式推導(dǎo)遠(yuǎn)大于邏輯演繹。
5、其實(shí)我最不關(guān)注的是性能問(wèn)題, 因?yàn)殡S著摩爾定律,單位計(jì)算單元的性價(jià)比會(huì)無(wú)限高,但Golang既然提出它的性能逼近C,那我還是提一下吧, 當(dāng)然,Erlang也還可以, 雖然比Java慢但跟Python一個(gè)檔次。
6、再談?wù)剤?bào)錯(cuò)機(jī)制, 因?yàn)镋rlang的的報(bào)錯(cuò)信息太讓人糾結(jié)了, 起初以為我不會(huì)看出錯(cuò)信息, 后來(lái)也使用了Sasl, 還是不夠直觀,甚至有時(shí)要用工具分析crash文件來(lái)定位問(wèn)題,還是跟Erlang的哲學(xué)有關(guān), 在Erlang中一切都是并行的, 所以它根本不care是物理哪一行出錯(cuò), 只跟Actor綁定, 然后告訴你Actor的ID和出錯(cuò)代號(hào), 你自己憑經(jīng)驗(yàn)去分析吧,這樣做的好處是可以很方便定位出并行中出現(xiàn)的問(wèn)題,但凡事都是相對(duì)的, 在這一點(diǎn)上有點(diǎn)糾枉過(guò)正,根據(jù)我的經(jīng)驗(yàn), 絕大部分時(shí)候我只希望先給我明確的指出哪一行出錯(cuò)了好嗎? 甚至把順序的backtrace用完整的英文句子打印出來(lái)好嗎?至于并行中的錯(cuò)誤及時(shí)在命令式多線程語(yǔ)言中是不常見(jiàn)的,雖然并不是沒(méi)有, 但遇到錯(cuò)誤我再費(fèi)勁去調(diào)試好了, 但并不是所有的邏輯都用并行的思維去定位問(wèn)題, 我甚至認(rèn)為, 對(duì)于一個(gè)系統(tǒng)不完全是并行也不完全是串行,跟好比我們衡量世界不能單純的唯物也不能完全的唯心一樣, 這一點(diǎn)Golang就做了很好的折中, 不需要并行的時(shí)候你老老實(shí)實(shí)的寫(xiě)串行代碼, 需要并行的時(shí)候也有較復(fù)雜的機(jī)制來(lái)應(yīng)對(duì), 合乎情理。
7、再說(shuō)說(shuō)招人吧, 以前招過(guò)好幾個(gè)C出來(lái)的人,說(shuō)實(shí)話水平很好, 可以一周就完成一個(gè)小組件, libevent用的熟的很,后來(lái)我逼人家用Erlang,結(jié)果把人家逼走了,至今我還很后悔, 自己的一廂情愿強(qiáng)加在別人身上真是太不合適了,但我招純Erlang出來(lái)的人,可以說(shuō)比招objc的人還難, 沒(méi)有人,空談技術(shù)的優(yōu)雅性首先就是不靠譜的,再看看郵件列表, Golang的活躍度明顯比Erlang高很多,基本逼近Ruby,更重要的是,根本不擔(dān)心Golang的人才,因?yàn)橹灰煜ython/C/Ruby/或者C++, 基本可以實(shí)現(xiàn)半天入門(mén), 之后就可以噼里啪啦邊搜資料邊干活了,雖然有足夠的深度,但門(mén)檻極其平緩,工程人員也可以復(fù)用很多已有的知識(shí)。 Erlang在這一點(diǎn)其實(shí)跟第一點(diǎn)硬傷有關(guān),大部分人學(xué)一周都摸不著頭腦,不是每個(gè)人的抽象思維和世界觀都是一樣的好嗎, 所以函數(shù)式編程盡管不比命令式語(yǔ)言起步晚,但始終學(xué)的人很少,這就是歷史, 對(duì)于大部分人, 更希望解決問(wèn)題,創(chuàng)造價(jià)值,而不是數(shù)學(xué)來(lái)推導(dǎo)去。?
8、最后我建議, 如果你是玩c/c++的, 現(xiàn)在開(kāi)始學(xué)Golang,是最好的時(shí)機(jī), 跟一門(mén)靠譜的語(yǔ)言一起成長(zhǎng), 這種感覺(jué)非常棒, 你用Erlang折騰1個(gè)應(yīng)用, 用Go恐怕都完成了10個(gè)開(kāi)源項(xiàng)目, 當(dāng)然,也要結(jié)合自己的口味, Golang就是Sublime Text, Erlang就是Emacs相信自己的判斷,相信自己的邏輯。?
?
評(píng)論
查看更多