C++併發程式設計框架Theron(1)——Actor模型介紹

無鞋童鞋發表於2017-07-09

1 說在前面的話


這裡寫圖片描述

  Theron是近些年發展起來的一個非常不錯的C++併發程式設計框架,最近有詳細閱讀Theron的相關資料,發現它思想非常有條理,結構很明朗,非常適合專案開發。其實Theron國內研究還是非常少的,目前還沒有看到什麼公開專案使用該框架。但是這並不代表Theron不夠優秀,一件新鮮事物要被眾人接受自然需要經受一段時間的考驗,所以我覺得自己應該盡一點微薄之力來當一名小小的傳播者。當然,這點抬手之舉相比較原作者的貢獻簡直不值得一提,看了所有Theron官網上開源的資料與原始碼,你就會感嘆為何有這麼詳細的解釋與示例,這不正是傳說中註釋比原始碼還要長的開源庫嗎?!作者的耐心與努力值得我們每一個人豎起大拇指。
  此外,我也需要點明,你只要有一些C/C++經驗直接閱讀Theron官網的資料也一定能有很多收穫。所以我後面所有的博文也僅僅是起一個翻譯與自己見解介紹的作用,如果你有什麼困惑的地方,那你不妨直接去Theron官網查詢相應估計會有更好的理解。好了,廢話不多說,讓我們進入正題吧。
2 Theron是什麼

這裡寫圖片描述
圖1 執行緒執行圖

  近些年來,多執行緒開發與分散式開發受到越來越多人的關注。但是有過多執行緒開發與除錯的人都知道,它的複雜性,除錯難,易出錯,記憶體共享,訊息同步足以令每個開發者望而生畏,每寫一條語句都想放棄查實其他開發方案。如圖1所示,一個執行緒在多執行緒系統中執行的狀態是要考慮很多方面的,現實開發中的複雜度更是超乎我們的想象。
  當然,共享記憶體的多執行緒開發中鎖機制的引入,一定程度上能夠保證執行緒同步,邏輯一致性。但是鎖機制帶來的資源消耗,效率低下問題,甚至有時候帶來死鎖等等一系列問題,不但沒有得到想要的,而且還失去更多。
  圖2前兩行圖展示了鎖帶來堵塞的問題,每個時刻只能允許一個執行緒工作(解鎖的鑰匙每次只有一個人能拿到),如同只能允許一個人蹲馬桶一樣,後面的人必須排隊,所以效率可想而知是很低的。

這裡寫圖片描述
圖2 共享記憶體的多執行緒鎖機制的比喻

  而圖2第三行展示了Theron框架基於Actor模型的工作機制,它們通過訊息通訊來多執行緒工作。那Actor模型這種訊息通訊的工作機制到底是怎樣的呢?它的優勢在哪裡?這一篇博文我將主要圍繞Actor模型來叩開Theron框架的大門。
3 Actor模型
 3.1 介紹
  Theron框架是一個基於Actor模型的併發程式設計的C++庫。而Actor模型使得Theron框架可以直接有效的建立並行分散式的應用。Theron框架提供了很多輕量便攜的函式介面API,可以使用在Linux,Windows,Mac,ARM和Matlab環境。
  我們知道物件導向程式設計中使用的是Object模型,宣揚一切皆是物件,資料+行為=物件。而Actor模型則認為一切皆是Actor,Actor模型內部的狀態由自己的行為維護,外部執行緒不能直接呼叫物件的行為,必須通過訊息才能激發行為,也就是使用訊息傳遞機制來代替Object模型的成員方法的呼叫,這樣就保證Actor內部資料只能被自己修改。Actor模型=資料+行為+訊息。
  但是C++是一種物件導向的語言,所以最終還是通過類來封裝這種actor的機制,多執行緒的實現也是依靠記憶體共享的多執行緒機制設計的,只不過這些事情Theron原始碼已經幫我們完成了,我們直接使用它給出的類介面即可。Theron框架的多執行緒基礎支援pthreads,Windows threads,boost::thread和C++11 threads四種傳統型別來構建。多說一嘴,因為Theron框架在C++中說到底還是通過類封裝實現Actor模型的,自然我們直接通過類物件呼叫類中方法資料。但是為了保證Theron框架生態的完整性,並且真正體現actor模型的優越性,我們還是不要如此為好。
  基於Object模型與Actor模型區別如圖3所示。

這裡寫圖片描述
(a)
這裡寫圖片描述
(b)
圖3 基於Object機制與基於Actor機制的比較

  從圖中可以看到,類A的物件成員方法呼叫類B的物件成員方法需要經過A::call呼叫B::called方法,然後等待B::called方法執行完成並且返回響應,最後A::call繼續上次呼叫的地方後面執行下去。而在Actor模型中,Actor A先傳送訊息給Actor B,然後即刻就返回繼續執行下面的程式,而Actor B中收到訊息被喚醒和Actor A並行執行下去。
  至此,Actor模型就可以看出這種訊息機制的執行緒呼叫最大好處是非阻塞的,多個執行緒可以同時併發進行,無需等待被呼叫方法執行完成返回訊息的響應。當然,看到此處大家或許跟我一樣有一點困惑的地方,即萬一我們後面的程式需要立即使用它返回的響應訊息怎麼辦呢?其實這也算Actor存在的一點不足之處,需要我們在設計多執行緒前考慮你的程式到底適不適合這種機制,後面我們會再詳細描述。
 3.2 Actor模型與共享記憶體模型不同點
  Actor這種獨立併發的模型,與另一種共享記憶體模型完全相反。Actor之間通過訊息傳遞方式進行合作,相互執行緒獨立。隨著多核時代和分散式系統的到來,共享記憶體模型其實不適合開發的。我們以酒店廚房做菜為例,如圖4所示。

這裡寫圖片描述
圖4 Actor模型與共享記憶體模型的比喻圖示

  ①、單執行緒程式設計,如圖4(a)——猶如酒店只有一個廚師員工(一個執行緒),所有菜按點菜順序與工序完成到底就行;
  ②、共享記憶體的多執行緒程式設計,如圖4(b)——猶如酒店廚房是由洗菜工,刀工,掌勺,服務員等(每個人是一個執行緒),他們之間的確能通過合作能比一個廚師完成所有工序要快。我們需要考慮的是菜相當於是他們共享的資源,每次只能一個人在對其做處理,雖然有多道菜品,但是總會在穿插間存在等待。
  ③、Actor模型的多執行緒程式設計,如圖4(c)——猶如酒店有多個廚師,分別是川菜師傅,魯菜師傅,徽菜師傅等等,他們只要接到客人點菜的需求,整個人獨自完成相對應菜系的工序,之間不管對方師傅要幹嘛,如此多執行緒工作就大大增加了效率,並且不存在互相等待資源的情況,做好了自己發訊息給服務員端菜即可。
  這樣我們就可以看出Actor模型非同步訊息傳遞來觸發程式並行執行,雖然不如直接呼叫來的直接而方便,但是它可以讓大量訊息真正意義上同步執行。同時訊息讓Actor之間解耦,訊息發出去之後執行成功與否,耗時多少等等只要沒有訊息傳遞回來,一切都不在與傳送方有任何關聯。這樣也保證了,我們不需要在共享環境中與同步鎖,互斥體等常用基礎多執行緒元素打交道。
 3.3 Actor模型的優缺點
  優點沒什麼再需要闡述的了,上面已經介紹的很詳細,下面我們來看看它到底存在什麼缺點,瞭解缺點對我們什麼時候使用Actor模型有很大的規劃作用。
  ①、每個Actor雖然是獨立執行的,但是一旦同時接收到多個訊息,一次也僅能處理一條訊息,也就是按訊息佇列處理;
  ②、Actor間非同步執行,通過訊息的傳遞實現協同。所以一個Actor內部出現執行錯誤很可能造成整個程式的錯誤——比如一個或多個其他Actors可能一直等待它反饋的訊息。所以我們一定需要好好的處理Actors的例外事件,並且有容錯機制及時反饋錯誤資訊給其他等待中的Actors;
  ③、Actor模型也存在死鎖問題,也有可能遇到它們之間互相等待訊息,所以可以使用超時設定的功能打破這個死鎖情況;
  ④、從上面的闡述我們也能窺探一二,並不是所有的應用開發都很好適合Actor模型。當且僅當我們可以將問題分為多個小模組,並且它們各自是獨立執行的,僅個別地方需要交流。如果多執行緒間需要頻繁互動,存在交叉的環境,其實Actor模型的效率優勢也就不復存在了,也就失去了其訊息呼叫並行執行的必要性。

4 小結 
  這篇博文主要還是開個Theron框架的開頭,主要介紹Theron框架的基石Actor模型,至於Theron框架的使用,函式介面,各種小示例我也會在今後抽空一一介紹。Actor併發模型實際上在很多語言上已經有使用,但是此次Theron框架將其封裝到C++開發上,真正給我們C++程式開發帶來了很大的便利。
  以上是個人學習記錄,由於能力和時間有限,如果有錯誤望讀者糾正,謝謝!
  轉載請註明出處:http://blog.csdn.net/FX677588/article/details/74359823


  參考文獻:
  Theron框架官網http://www.theron-library.com/
  為什麼Actor模型是高併發事務的終極解決方案?http://www.jdon.com/45728
  Actor模型的優缺點http://blog.chinaunix.net/uid-21712186-id-5000328.html
  詳解Theron通過Actor模型解決C++併發程式設計的一種思維http://www.mahaixiang.cn/bcyy/954.html
  

相關文章