• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            loop_in_codes

            低調(diào)做技術(shù)__歡迎移步我的獨(dú)立博客 codemaro.com 微博 kevinlynx

            Erlang使用感受

            用erlang也算寫了些代碼了,主要包括使用RabbitMQ的練習(xí),以及最近寫的kl_tservericerl。其中icerl是一個(gè)實(shí)現(xiàn)了Ice的erlang庫(kù)。

            erlang的書較少,我主要讀過(guò)<Programming Erlang>和<Erlang/OTP in Action>。其實(shí)erlang本身就語(yǔ)言來(lái)說(shuō)的話比較簡(jiǎn)單,同ruby一樣,類似這種本身目標(biāo)是應(yīng)用于實(shí)際軟件項(xiàng)目的語(yǔ)言都比較簡(jiǎn)單,對(duì)應(yīng)的語(yǔ)法書很快可以翻完。

            這里我僅談?wù)勛约涸诰帉慹rlang代碼過(guò)程中的一些感受。

            語(yǔ)法

            erlang語(yǔ)法很簡(jiǎn)單,接觸過(guò)函數(shù)式語(yǔ)言的程序員上手會(huì)很快。它沒(méi)有類似common lisp里宏這種較復(fù)雜的語(yǔ)言特性。其語(yǔ)法元素很緊湊,不存在一些用處不大的特性。在這之前,我學(xué)習(xí)過(guò)ruby和common lisp。ruby代碼寫的比common lisp多。但是在學(xué)習(xí)erlang的過(guò)程中我的腦海里卻不斷出現(xiàn)common lisp里的語(yǔ)法特性。這大概是因?yàn)閏ommon lisp的語(yǔ)法相對(duì)ruby來(lái)說(shuō),更接近erlang。

            編程模式

            erlang不是一個(gè)面向?qū)ο蟮恼Z(yǔ)言,它也不同common lisp提供多種編程模式。它的代碼就是靠一個(gè)個(gè)函數(shù)組織出來(lái)的。面向?qū)ο笳Z(yǔ)言在語(yǔ)法上有一點(diǎn)讓我很爽的是,其函數(shù)調(diào)用更自然。erlang的接口調(diào)用就像C語(yǔ)言里接口的調(diào)用一樣:

            func(Obj, args)
            Obj->func(args)
            

            即需要在函數(shù)第一個(gè)參數(shù)傳遞操作對(duì)象。但是面向?qū)ο笳Z(yǔ)言也會(huì)帶來(lái)一些語(yǔ)法的復(fù)雜性。如果一門語(yǔ)言可以用很少的語(yǔ)法元素表達(dá)很多信息,那么我覺(jué)得這門語(yǔ)言就是門優(yōu)秀的語(yǔ)言。

            表達(dá)式/語(yǔ)句

            erlang里沒(méi)有語(yǔ)句,全部是表達(dá)式,意思是所有語(yǔ)法元素都是有返回值的。這實(shí)在太好了,全世界都有返回值可以讓代碼寫起來(lái)簡(jiǎn)單多了:

                Flag = case func() of 1 -> true; 0 -> false end, 
            

            命名

            我之所以不想寫一行python代碼的很大一部分原因在于這門語(yǔ)言居然要求我必須使用代碼縮進(jìn)來(lái)編程,真是不敢相信。erlang里雖然沒(méi)有此規(guī)定,卻也有不同的語(yǔ)法元素有大小寫的限定。變量首字母必須大寫,atom必須以小寫字母開(kāi)頭,更霸氣的是模塊命名必須和文件名相同。

            變量

            erlang里的變量是不可更改的。實(shí)際上給一個(gè)變量賦值,嚴(yán)格來(lái)說(shuō)應(yīng)該叫bound,即綁定。這個(gè)特性完全就是函數(shù)式語(yǔ)言里的特性。其帶來(lái)的好處就像函數(shù)式語(yǔ)言宣揚(yáng)的一樣,這會(huì)使得代碼沒(méi)有副作用(side effect)。因?yàn)槌绦蚶锏乃泻瘮?shù)不論怎樣調(diào)用,其程序狀態(tài)都不會(huì)改變,因?yàn)樽兞繜o(wú)法被改變。

            變量不可更改,直接意味著全局變量沒(méi)有存在的意義,也就意味著不論你的系統(tǒng)是多么復(fù)雜地被構(gòu)建出來(lái),當(dāng)系統(tǒng)崩潰時(shí),其崩潰所在位置的上下文就足夠找到問(wèn)題。

            但是變量不可改變也會(huì)帶來(lái)一些代碼編寫上的不便。我想這大概是編程思維的轉(zhuǎn)變問(wèn)題。erlang的語(yǔ)法特性會(huì)強(qiáng)迫人編寫非常短小的函數(shù),你大概不愿意看到你的函數(shù)實(shí)現(xiàn)里出現(xiàn)Var1/Var2/Var3這樣的變量,而實(shí)際上這樣的命名在命令式語(yǔ)言里其實(shí)指的是同一個(gè)變量,只不過(guò)其值不同而已。

            但是我們的程序總是應(yīng)該有狀態(tài)的。在erlang里我們通過(guò)不斷創(chuàng)建新的變量來(lái)存儲(chǔ)這個(gè)狀態(tài)。我們需要通過(guò)將這個(gè)狀態(tài)隨著我們的程序流程不斷地通過(guò)函數(shù)參數(shù)和返回值傳遞下去。

            atom

            atom這個(gè)語(yǔ)法特性本身沒(méi)問(wèn)題,它就同lisp里的atom一樣,沒(méi)什么意義,就是一個(gè)名字。它主要用在增加代碼的可讀性上。但是這個(gè)atom帶來(lái)的好處,直接導(dǎo)致erlang不去內(nèi)置諸如true/false這種關(guān)鍵字。erlang使用true/false這兩個(gè)atom來(lái)作為boolean operator的返回值。但erlang里嚴(yán)格來(lái)說(shuō)是沒(méi)有布爾類型的。這其實(shí)沒(méi)什么,糟糕的是,對(duì)于一些較常見(jiàn)的函數(shù)返回值,例如true/false,erlang程序員之間就得做約定。要表示一個(gè)函數(shù)執(zhí)行失敗了,我可以返回false、null、failed、error、nil,甚至what_the_fuck,這一度讓我迷惘。

            list/tuple

            erlang里的list當(dāng)然沒(méi)有l(wèi)isp里的list牛逼,別人整個(gè)世界就是由list構(gòu)成的。在一段時(shí)間里,我一直以為list里只能保存相同類型的元素,而tuple才是用于保存不同類型元素的容器。直到有一天我發(fā)現(xiàn)tuple的操作不能滿足我的需求了,我才發(fā)現(xiàn)list居然是可以保存不同類型的。

            list相對(duì)于tuple而言,更厲害的地方就在于頭匹配,意思是可以通過(guò)匹配來(lái)拆分list的頭和剩余部分。

            匹配(match)

            erlang的匹配機(jī)制是個(gè)好東西。這個(gè)東西貫穿了整個(gè)語(yǔ)言。在我理解看來(lái),匹配機(jī)制減少了很多判斷代碼。它試圖用一個(gè)期望的類型去匹配另一個(gè)東西,如果這個(gè)東西出了錯(cuò),它就無(wú)法完成這個(gè)匹配。無(wú)法完成匹配就導(dǎo)致程序斷掉。

            匹配還有個(gè)方便的地方在于可以很方便地取出record里的成員,或者tuple和list的某個(gè)部分,這其實(shí)增強(qiáng)了其他語(yǔ)法元素的能力。

            循環(huán)

            erlang里沒(méi)有循環(huán)語(yǔ)法元素,這真是太好了。函數(shù)式語(yǔ)言里為什么要有循環(huán)語(yǔ)法呢?common lisp干毛要加上那些復(fù)雜的循環(huán)(宏),每次我遇到需要寫循環(huán)的場(chǎng)景時(shí),我都誠(chéng)惶誠(chéng)恐,最后還是用遞歸來(lái)解決。

            同樣,在erlang里我們也是用函數(shù)遞歸來(lái)解決循環(huán)問(wèn)題。甚至,我們還有l(wèi)ist comprehension。當(dāng)我寫C++代碼時(shí),我很不情愿用循環(huán)去寫那些容器遍歷代碼,幸運(yùn)的是在C++11里通過(guò)lambda和STL里那些算法我終于不用再寫這樣的循環(huán)代碼了。

            if/case/guard

            erlang里有條件判定語(yǔ)法if,甚至還有類似C語(yǔ)言里的switch…case。這個(gè)我一時(shí)半會(huì)還不敢評(píng)價(jià),好像haskell里也保留了if。erlang里同haskell一樣有g(shù)uard的概念,這其實(shí)是一種變相的條件判斷,只不過(guò)其使用場(chǎng)景不一樣。

            進(jìn)程

            并發(fā)性支持屬于erlang的最大亮點(diǎn)。erlang里的進(jìn)程概念非常簡(jiǎn)單,基于消息機(jī)制,程序員從來(lái)不需要擔(dān)心同步問(wèn)題。每個(gè)進(jìn)程都有一個(gè)mailbox,用于緩存發(fā)送到此進(jìn)程的消息。erlang提供內(nèi)置的語(yǔ)法元素來(lái)發(fā)送和接收消息。

            erlang甚至提供分布式支持,更酷的是你往網(wǎng)絡(luò)上的其他進(jìn)程發(fā)送消息,其語(yǔ)法和往本地進(jìn)程發(fā)送是一樣的。

            模塊加載

            如果我寫了一個(gè)erlang庫(kù),該如何在另一個(gè)erlang程序里加載這個(gè)庫(kù)?這個(gè)問(wèn)題一度讓我迷惘。erlang里貌似有對(duì)庫(kù)打包的功能(.ez?),按理說(shuō)應(yīng)該提供一種整個(gè)庫(kù)加載的方式,然后可以通過(guò)手動(dòng)調(diào)用函數(shù)或者指定代碼依賴項(xiàng)來(lái)加載。結(jié)果不是這樣。

            erlang不是按整個(gè)庫(kù)來(lái)加載的,因?yàn)橐矝](méi)有方式去描述一個(gè)庫(kù)(應(yīng)該有第三方的)。當(dāng)我們調(diào)用某個(gè)模塊里的函數(shù)時(shí),erlang會(huì)自動(dòng)從某個(gè)目錄列表里去搜索對(duì)應(yīng)的beam文件。所以,可以通過(guò)在啟動(dòng)erlang添加這個(gè)模塊文件所在目錄來(lái)實(shí)現(xiàn)加載,這還是自動(dòng)的。當(dāng)然,也可以在erlang shell里通過(guò)函數(shù)添加這個(gè)目錄。

            OTP

            使用erlang來(lái)編寫程序,最大的優(yōu)勢(shì)可能就是其OTP了。OTP基本上就是一些隨erlang一起發(fā)布的庫(kù)。這些庫(kù)中最重要的一個(gè)概念是behaviour。behaviour其實(shí)就是提供了一種編程框架,應(yīng)用層提供各種回調(diào)函數(shù)給這個(gè)框架,從而獲得一個(gè)健壯的并發(fā)程序。

            application behaviour

            application behaviour用于組織一個(gè)erlang程序,通過(guò)一個(gè)配置文件,和提供若干回調(diào),就可以讓我們編寫的erlang程序以一種統(tǒng)一的方式啟動(dòng)。我之前寫的都是erlang庫(kù),并不需要啟動(dòng),而是提供給應(yīng)用層使用,所以也沒(méi)使用該behaviour。

            gen_server behaviour

            這個(gè)behaviour應(yīng)該是使用頻率很高的。它封裝了進(jìn)程使用的細(xì)節(jié),本質(zhì)上也就是將主動(dòng)收取消息改成了自動(dòng)收取,收取后再回調(diào)給你的模塊。

            supervisor behaviour

            這個(gè)behaviour看起來(lái)很厲害,通過(guò)對(duì)它進(jìn)行一些配置,你可以把你的并發(fā)程序里的所有進(jìn)程建立成樹狀結(jié)構(gòu)。這個(gè)結(jié)構(gòu)的牛逼之處在于,當(dāng)某個(gè)進(jìn)程掛掉之后,通過(guò)supervisor可以自動(dòng)重新啟動(dòng)這個(gè)掛掉的進(jìn)程,當(dāng)然重啟沒(méi)這么簡(jiǎn)單,它提供多種重啟規(guī)則,以讓整個(gè)系統(tǒng)確實(shí)通過(guò)重啟變成正常狀態(tài)。這實(shí)在太牛逼了,這意味著你的服務(wù)器可以7x24小時(shí)地運(yùn)行了,就算有問(wèn)題你也可以立刻獲得一個(gè)重寫工作的系統(tǒng)。

            熱更新

            代碼熱更新對(duì)于一個(gè)動(dòng)態(tài)語(yǔ)言而言其實(shí)根本算不上什么優(yōu)點(diǎn),基本上動(dòng)態(tài)語(yǔ)言都能做到這一點(diǎn)。但是把熱更新這個(gè)功能加到一個(gè)用于開(kāi)發(fā)并發(fā)程序的語(yǔ)言里,那就很牛逼了。你再一次可以確保你的服務(wù)器7x24小時(shí)不停機(jī)維護(hù)。

            gen_tcp

            最開(kāi)始我以為erlang將網(wǎng)絡(luò)部分封裝得已經(jīng)認(rèn)不出有socket這個(gè)概念了。至少,你也得有一個(gè)牛逼的網(wǎng)絡(luò)庫(kù)吧。結(jié)果發(fā)現(xiàn)依然還是socket那一套。然后我很失望。直到后來(lái),發(fā)現(xiàn)使用一些behaviour,加上調(diào)整gen_tcp的一些option,居然可以以很少的代碼寫出一個(gè)維護(hù)大量連接的TCP服務(wù)器。是啊,erlang天生就是并發(fā)的,在傳統(tǒng)的網(wǎng)絡(luò)模型中,我們會(huì)覺(jué)得使用one-thread-per-connection雖然簡(jiǎn)單卻不是可行的,因?yàn)閠hread是OS資源,太昂貴。但是在erlang里,one-process-per-connection卻是再自然不過(guò)的事情。你要是寫個(gè)erlang程序里面卻只有一個(gè)process你都不好意思告訴別人你寫的是erlang。process是高效的(對(duì)我們這種二流程序員而言),它就像C++里一個(gè)很普通的對(duì)象一樣。

            在使用gen_tcp的過(guò)程中我發(fā)現(xiàn)一個(gè)問(wèn)題,不管我使用哪一種模型,我竟然找不到一種溫柔的關(guān)閉方式。我查看了幾個(gè)tutorial,這些混蛋竟然沒(méi)有一個(gè)人提到如何去正常關(guān)閉一個(gè)erlang TCP服務(wù)器。后來(lái),我沒(méi)有辦法,只好使用API強(qiáng)制關(guān)閉服務(wù)器進(jìn)程。

            Story

            其實(shí),我和erlang之間是有故事的。我并不是這個(gè)月開(kāi)始才接觸erlang。早在2009年夏天的時(shí)候我就學(xué)習(xí)過(guò)這門語(yǔ)言。那時(shí)候我還沒(méi)接觸過(guò)任何函數(shù)式語(yǔ)言,那時(shí)候lua里的閉包都讓我覺(jué)得新奇。然后無(wú)意間,我莫名其妙地接觸了haskell(<Real World Haskell>),在我決定開(kāi)始寫點(diǎn)什么haskell練習(xí)時(shí),我發(fā)現(xiàn)我無(wú)從下手,最后,Monads把我嚇哭了。haskell實(shí)在太可怕了。

            緊接著我懷揣著對(duì)函數(shù)式語(yǔ)言的濃烈好奇心看到了erlang。當(dāng)我看到了concurrent programming的章節(jié)時(shí),在一個(gè)燥熱難耐的下午我的領(lǐng)導(dǎo)找到了我,同我探討起erlang對(duì)我們的網(wǎng)游服務(wù)器有什么好處。然后,我結(jié)束我了的erlang之旅。

            時(shí)隔四年,這種小眾語(yǔ)言,居然進(jìn)入了中國(guó)程序員的視野,并被用于開(kāi)發(fā)網(wǎng)頁(yè)游戲服務(wù)器。時(shí)代在進(jìn)步,我們總是被甩在后面。

            posted on 2013-05-09 21:24 Kevin Lynx 閱讀(5480) 評(píng)論(0)  編輯 收藏 引用 所屬分類: erlang

            久久精品国产清自在天天线| 日韩精品久久无码中文字幕| 久久精品水蜜桃av综合天堂| 亚洲国产精品无码久久| 青青青国产精品国产精品久久久久| 中文字幕一区二区三区久久网站 | 国产精品久久久香蕉| 国产综合久久久久久鬼色| 香蕉久久永久视频| 精品免费tv久久久久久久| 久久久这里有精品| 粉嫩小泬无遮挡久久久久久| 99久久免费国产精精品| 少妇精品久久久一区二区三区| 久久Av无码精品人妻系列 | 亚洲va久久久噜噜噜久久| 国内精品久久久久久99蜜桃| 精品人妻伦九区久久AAA片69| 国产精品久久久久久久| 久久无码国产| 久久九九久精品国产免费直播| 大伊人青草狠狠久久| 国产精品免费看久久久香蕉| 99久久国产主播综合精品| 日本五月天婷久久网站| 久久精品国产一区二区电影| 国产精品久久久久久福利漫画| 亚洲精品无码久久一线| 久久久久亚洲AV无码专区桃色 | 久久久久久久亚洲精品| 久久99精品国产一区二区三区| 久久精品成人欧美大片| 尹人香蕉久久99天天拍| 久久夜色精品国产www| 99久久精品国产一区二区三区| 久久综合给久久狠狠97色| 亚洲av成人无码久久精品| 久久天天躁夜夜躁狠狠躁2022 | 国产精品久久久久久吹潮| 狠狠色狠狠色综合久久| 久久久久久久97|