欧美性猛交黑人xxxx,成人毛片一区二区三区,久久综合九色综合精品,男的把j放进女人下面视频免费

Haskell語言和Erlang語言實現P2P協議的對比

  • 發布于:2020-02-03
  • 263 人圍觀

Jesper Louis Andersen根據他分別使用Haskell和Erlang語言編寫兩個BitTorrent客戶端——Combinatorrent和Etorrent的經驗,向聽眾闡述運用這兩種語言進行開發的優勢和困難。他特別詳細說明了如何善用這兩種語言各自的精華之處,充分發揮消息傳遞機制強健的并發能力。

個人簡介
Jesper熱愛鉆研編程語言,尤其是并發與函數式編程。他擔任領導人和主要開發者的兩個開源項目,分別用Erlang和Haskell語言實現了BitTorrent P2P內容分發協議,并在項目中盡量發揮了各自實現語言的長處。

 大家好,我是Sadek Drobi,現在在GoTo大會上采訪Jesper Louis Anderson。Jesper能向大家介紹下你自己嗎?

大家好,我是Jesper。我就是丹麥的一個編程語言技術宅,喜歡擺弄編程語言,擺弄各種類型的編程語言,通過用它們實現各種東西來達到鉆研語言的目的。我鉆研的對象以函數式語言為主,但也會使用和研究命令式編程語言。盡量一個都不放過。

 我知道你用Erlang和Haskell兩種語言都實現過BitTorrent協議。是什么原因令你這樣做?

一開始我只是想學習語言。我的想法是說,要學一門語言,必須用它來做點什么東西,一定要真正用過,不能只嘗試那些玩具一樣的例子。用一門語言去解決真正的問題之后,才能確實掌握它的用法。所以我就帶著這種觀念開始學習Erlang,因為BitTorrent客戶端對于并發和并行能力有很強烈的需求,我就想到Erlang應該適合用來實現BitTorrent客戶端。

開發過程的動力首先是自我挑戰“我能做出來嗎?”,其次是學習語言的愿望,希望去理解語言的機理。這些就是我用Erlang語言編寫BitTorrent客戶端的動機。后來嘗試Haskell語言的理由也是一樣的。第二次因為已經實現過BitTorrent協議,可以說對問題域相當熟悉,知道它的原理,知道那些黑暗的角落,所有不好下手的地方都清楚。但即便如此,實現工作仍然不簡單,還是有一些困難要克服。不過畢竟提前知道哪些地方可能出問題,新語言學起來更快一點。

因為可以集中精力在新語言的特性上面。要做的事情沒變,還是實現BitTorrent協議,只剩下語言特性需要鉆研。總之目標是學習語言,提高我自己對Haskell語言的認識水平。

 那就等于說前后兩次的經驗是完全不同的:第一次你學習如何實現BitTorrent客戶端,第二次你學習Haskell語言,用Haskell把事情重做一邊?

是這樣。

 你一開始偏偏選了Erlang,它特別在哪里?

特別在哪里?我覺得Erlang有兩點很特別:其一是它具有一種被動的錯誤處理觀念,對于可能發生的錯誤,你要準備萬全的應變計劃去面對一切可能的情況,把錯誤清理掉或者盡量糾正,盡量保證程序能繼續運行下去,不退出或死機。系統盡其所能維持運轉。這種觀念會影響你對錯誤的處理方式,造成Erlang程序獨特的寫作方式。這是Erlang非常突出的特點,引起我的興趣和喜好。

第二個特點是它的內部模型,Erlang程序里面存在大量的小進程,而每個進程完全獨立于其他進程。在一般的編程語言里面,多個進程之間往往共享內存空間。Erlang從VM的角度來看不是這個樣子。當然從更底層的角度,從內核的角度來看,還是存在一個共享的內存空間。但是在Erlang的思維里面,每個進程被認為是獨立的。這樣的模型有其代價,即當某些內容要從一個進程轉移到另一個進程的時候,必須完全復制一份。

在我的認知里面,唯有Erlang完全采用這樣的模型。也許有些玩具語言也這樣,但至少在比較流行的語言里面,沒有第二個這樣做的。一般的語言都采取共享內存的概念,不會讓每個進程完全獨立,甚至有自己的垃圾收集器。所以我認為這是Erlang的第二個獨特的地方。

 Erlang的特點正好有利于你實現BitTorrent客戶端。那么當你換到Haskell語言的時候,沒有了這些特性,你用什么東西來代替?

Haskell是共享內存的,它也可以fork進程什么的,但內存確實是共享的。好在它有持久化的不可變性。利用persistence immutability的概念,即使沒有完全獨立的進程,也能取得很好的效果。如果我向另一個進程發送一個數據結構,對方進程得到的本質上是一個副本。假如我方改變剛才發送的數據結構,將得到一個新版本的數據結構,持久化的概念使雙方不受變化的影響,對方看到的原始舊版本還是有效的。

大體上可以把這種特性看成給數據加上版本管理,它化解了進程不完全獨立的問題。函數式語言Haskell具備不可變性和持久化的特點,為它解決很多這方面的問題。

 錯誤處理在Haskell里面是怎樣的?

這方面有點意思,因為Haskell的錯誤處理觀念不像Erlang那樣被動。Haskell程序出錯的時候會拋出異常,這種錯誤處理方式看起來沒什么特別。然而Haskell的最大特點是它具有非常強的類型系統。所以當你主動發揮類型系統的表達能力的時候,類型系統會防止你寫出存在錯誤的程序,從根子上阻止錯誤發生,這樣就達到減少程序中錯誤和錯誤狀態的目的。從這個意義上說,Haskell語言的錯誤處理觀念是主動、積極的。

這里頭有一個要點,即對待類型系統有兩種態度。如果你覺得不喜歡類型系統,那么類型系統往往就發揮不出它的效用。空有一個類型系統不去充分利用,而以勉強的態度去將就適應存在類型系統這個事實,那么類型系統就會干擾刺激你。假如你換一種態度,把類型系統看作描述程序的手段來積極地運用,那么當程序中存在錯誤的時候,有很大幾率被類型系統所揭發,起到保護的作用。

所以要注意類型的用法,盡量讓類型檢查在出錯的時候給你指出來:“這里不對!”甚至直接給你指出錯在哪一行。所以我這樣總結Haskell和Erlang的異同,它們都極重視程序的正確性和健壯性,但在取得健壯程序的方式上,Haskell偏向于主動的方式,Erlang偏向于被動的方式。

我在寫Haskell客戶端的時候,處理異常的做法有點像Erlang的錯誤處理方式。我部分地實現了Erlang的錯誤處理機制,但沒有全盤復制。所以當程序死掉的時候就死掉了,不會像Erlang那樣死不了,也不存在重啟一部分系統的情況。

 Erlang有actor,而Haskell沒有,你是怎么做的?

用了迂回的辦法。Actor模型是個老模型,從1970年代就出現了,有著嚴格定義。Erlang在某種意義上實現了Actor模型,它的“類Actor”特征非常鮮明。我開始編寫Haskell客戶端的時候,做了一個決定:既然已經有一個用Erlang風格的actor搭建的進程模型,何不直接把它套用到Haskell。于是我費了一些時間來做這件事,用了Haskell并發庫和CML。CML我以前就用過一陣子。我在CML的基礎上重新實現了actor模型。后來發現CML不適合做這件事,而且我不滿意CML內部有些抽象泄露的情況。

所以我決定把CML那部分換成軟件事務內存(software transactional memory)——STM模型,正好Haskell有這個。系統最后的樣子,最底層是STM模型,上面是STM模型營造出來的一個“類Actor”的世界,Haskell客戶端的搭建工作就在這個世界里面進行。大體上是這樣的過程。

 在STM上面實現起來容易嗎?

是的,我覺得挺容易的。就是有一個地方跟Erlang不一樣:Erlang是向進程發送消息。發送消息的目標,那個標識符代表了一個進程。Haskell客戶端通過channel來發送消息,消息的發送途徑是通道。這一點與Haskell屬于靜態類型語言有關。通道因為類型是確定的,用起來肯定簡單很多。而進程的話會遇到一個很難回答的問題:“那個進程的輸入類型是什么?”因為肯定會遇到一些別的類型,別的很復雜的類型,類型層面的問題不容易解決。

通道的話,在語言層面幾乎不需要操心類型的問題。所以在Haskell這樣的靜態類型語言里面,通道方案最為簡單。因此當我編寫Haskell版的BitTorrent客戶端的時候,我決定采用通道,而不在這方面照搬Erlang模型。另外由于STM已經包含了通道基本類型,基本不用再費什么事。只有一件事情需要另外準備,即同時接收多條通道的能力,而STM連這方面的規劃功能都給你準備好了。基本上就是萬事具備的樣子。

我記憶里面,只補充了一些進程處理結構和一些監控結構,用來重置部分系統,或者處理連接突然斷開之類的事情。總量不超過四、五十行代碼,就足以將大部分的Erlang模型復制過來,重新在Haskell里面實現。

 在某種程度上,你的Erlang實現影響了你的Haskell實現。那么你的Haskell實現有沒有反過來影響Erlang實現?可以說說嗎?

有的。我先有的Erlang實現,然后當我用Haskell重新實現的時候,突然發現因為有通道這個東西,某些部分必須推翻掉。Haskell版的編寫過程讓我對每個進程的相互關系有了更進一步的理解。我意識到有些進程存在用戶節點意義上的局部性,只對單個用戶節點有意義,還有一些進程存在Torrent意義上的局部性,比如只作用于某個完成了的Torrent。

例如有局部的進程,圍繞一個Torrent與一群用戶節點進行通信,然后有全局的、與多個Torrents通信的進程。請想象一個例子,假設你希望在系統中增加限制帶寬的設施,限制上行帶寬的占用量。這個東西是全局性的,因為你希望限制客戶端整體占用的帶寬。你還可以對每個Torrent單獨限制其占用量,這種情況屬于在Torrent意義上的局部。

繼續舉例的話,還有比如對單個用戶節點的限制,限制某節點允許占用的最大帶寬。思路大概就是這個樣子,我從這里頭總結出來——全局、Torrent意義上的局部、用戶節點意義上的局部——這些關于局部性的系統規律。Erlang實現根本沒考慮這些方面,它的基本思路就是一切都是互相聯系的。后來我按照新的思路回頭去翻新Erlang版的進程模型,看到一個進程知道說“哦,它是Torrent局部的進程”,那就把它放在這個地方。那個地方一定不能放一個全局的進程,不然它會同時含有多個Torrents的狀態。

這些關于進程定位的知識被回饋到Erlang客戶端,補其不足。大體上可以認為Haskell實現是第二次迭代,重新對Erlang實現進行局部修整算是第三次迭代。如果日后又對模型有了新的認識,那么出現第四次迭代也不足為奇。

萬企互聯
標簽: