LabVIEW的ActorFramework筆記

Stephen_Young發表於2024-08-07

1 前置知識儲備

自分散式計算出現以來,業界已經開始廣泛研究基於訊息傳遞程式設計模型的解決方案。關於訊息傳遞,Wikipedia 描述其廣泛定義主要包括:遠端過程呼叫(Remote Procedure Calls, RPC) 和 訊息傳遞介面(Message Passing Interface, MPI)。但是,如今我們所談到的訊息傳遞,通常是指 actor 模型(Actor Model)。作為一種通用的訊息傳遞程式設計模型,其起源於 20 世紀 70 年代,如今被廣泛用於構建大規模可伸縮分散式系統。

Actor 模型

一個 actor 定義為一個計算單元。所謂麻雀雖小,五臟俱全,每個 Actor 包含了儲存、通訊、計算等能力。在分散式系統中,通常包含了非常多的伺服器叢集,每一臺伺服器又包含了大量 actor 例項,它們共同構成了強大的平行計算能力。

Actor 的核心思想是 獨立維護隔離狀態,並基於訊息傳遞實現非同步通訊。圍繞其進行實現,actor 通常包含以下特徵:

每個 actor 持有一個郵箱(mailbox),本質上是一個佇列,用於儲存訊息。
每個 actor 可以傳送訊息至任何 actor。
每個 actor 可以透過處理訊息來更新內部狀態,對於外部而言,actor 的狀態是隔離的狀態(isolated state)。

為了便於通訊,actor 模型使用 非同步 訊息傳遞。訊息傳遞不使用任何中間實體,如:通道(channel)。由於 actor 模型的訊息是非同步傳遞的,中間可能會經過很長時間,甚至丟失,因此無法保證訊息到達目標 actor 時的順序。每個 actor 都完全獨立於任何其他例項,actor 之間的互動完全基於非同步訊息,因此能夠在很大程度上避免共享記憶體的存在問題。

任務排程

Actor 模型根據任務排程的方式可以分為兩種,分別是:

(1)基於執行緒(thread-based)的 actor 模型

基於執行緒的 actor 模型,其本質是為每一個 actor 分配一個獨立的“執行緒”。這裡的“執行緒”並不是嚴格意義的作業系統執行緒,而是廣泛意義的執行過程,它可以是執行緒、協程或虛擬機器執行緒。

在基於執行緒的 actor 模型中,每個 actor 獨佔一個執行緒,如果當前 actor 的郵箱為空,actor 會阻塞當前執行緒,等待接收新的訊息。在實現中,一般使用 receive 原語。

這種 actor 模型實現起來比較簡單,但是缺點也非常明顯,由於執行緒數量受到系統的限制,因此 actor 的數量也會受到限制。現階段,只有少部分 actor 模型採用基於執行緒的實現方式,如:Erlang、Scala Actor、Cloud Haskell。

(2)事件驅動(event-driven)的 actor 模型

在事件驅動的 actor 模型,actor 並不直接與執行緒耦合,只有在事件觸發(即接收訊息)時,才為 actor 的任務分配執行緒並執行。這種方式使用續體閉包(Continuation Closure)來封裝 actor 及其狀態。當事件處理完畢,即退出執行緒。透過這種方式,我們可以使用很少的執行緒來執行大量 actor 產生的任務。在實現中,一般使用 react 原語。

事件驅動的 actor 模型在訊息觸發時,會自動建立並分配執行緒。在這種過程中,一般的最佳化是將 actor 執行建立在底層的執行緒池之上,這些執行緒可以是執行緒、協程或虛擬機器執行緒。從概念上講,這種實現與 run loop、event loop 機制非常相似。

2 LabVIEW的AF示例

假設有學生和老師這兩個actor,學生有個“向老師交了一份兒作業”的方法;老師有“給學生的作業打分。”這個方法;

先來設計學生這個actor:

(1)新建一個空白的Project,並命名儲存為“AF_student_teacher.lvproj”:

(2)右鍵新建操作者Actor——Student:



student這個類我們還定義一個“姓名”的私有私有(私有欄位);並寫一個其“寫入”的方法:

(3)新建 靜態模板方法——交作業


“交作業”方法體程式碼:

(4)為“交作業”方法建立 訊息:

(5)測試“Student”Actor:


點選vi執行按鈕:

至此,第一個actor ——student設計完成。

相關文章