Peter Scarfe, Creator of Workers for LabVIEW, 在VIMP中搜索Worker進行安裝即可,本文檔基于Workers 3.1.1版本進行說明。
1. Workers的設計背景
雖然LabVIEW可以很容易地以非常高效的方式開發(fā)小型和獨立的任務,但對大多數(shù)人來說,開發(fā)一個更復雜的多線程應用程序,仍然是一個比較困難且耗時的過程。需要多個獨立循環(huán)、且健壯、可擴展、易于調(diào)試的應用程序需要時間和經(jīng)驗去開發(fā)。
Actor Framework采用LVOOP封裝設計,提供了增強的可伸縮性、可擴展、和優(yōu)先級隊列,但是它對新手開發(fā)人員來說理解相對復雜。所以作者希望可以做更多事情來幫助新手開發(fā)人員以一種更簡單、快速且輕松的方式開發(fā)出高質(zhì)量的應用程序,而無需具備LVOOP基礎,或是學習一些新的不熟悉的架構(gòu),于是在使用廣泛且被大家熟悉理解的QMH框架基礎上,并且為了提高開發(fā)效率集成一些腳本工具,便創(chuàng)建了Workers。
作者希望通過Workers可以提高新手和高級開發(fā)人員的生產(chǎn)力,讓他們以更低復雜度和更短的時間開發(fā)更大的項目。
2. Workers的特征
2.1 模塊化
一個Worker就是一個獨立的QMH(Queued Message Handler)模塊,類似搭積木一樣將它們組織在一起,通過多個Worker的協(xié)作,可以很輕松地創(chuàng)建它們的層次結(jié)構(gòu)來構(gòu)建應用程序的框架。模塊化設計還使得它們可以通過Create/Add Worker Tool被更好的復用和擴展,Workers被設計的小而靈活,并且可以被靜態(tài)或動態(tài)加載。
2.2 可擴展
Workers允許你通過使用Create/Add Worker Tool快速創(chuàng)建多個Worker來構(gòu)建程序的功能框架,大大減少開發(fā)時間和未來需要擴展的工作量,可以很方便地使用其它項目中開發(fā)好的Worker模塊,或創(chuàng)建自己的Worker模板在該腳本工具中進行使用。
2.3 優(yōu)先級消息隊列
參考Actor Framework中消息隊列設計改編而來,性能和限制基本與之一樣。它提供了一個多優(yōu)先級的消息隊列,包括Low、Normal(default)、High、Critical(Framework Only)四個優(yōu)先級,提供了更加靈活的消息優(yōu)先級處理方式。
2.4 調(diào)試器
一個框架的好壞取決于它的調(diào)試器!Workers Debugger一開始就是和Worker框架一起開發(fā)的,旨在幫助讓運行的代碼更加透明且易于導航。Task Manager顯示了所有正在運行的Workers的當前狀態(tài),并允許你跳轉(zhuǎn)到正在運行的克隆副本中以進行進一步調(diào)試。Message Log按時間順序列出所有Workers消息處理循環(huán)之間發(fā)送的消息,消息入隊和出隊列的時間和地點,以及Workers中哪里發(fā)生了錯誤,借助調(diào)試器可以很容易定位問題并直接跳轉(zhuǎn)到它們,以便立刻修復它們。
2.5 層次視圖工具
應用程序中所有的Workers的調(diào)用鏈層次關(guān)系是怎樣的?它們是被其它的Worker靜態(tài)還是動態(tài)進行加載的?層次視圖工具可以為你展示這些信息,通過平面視圖以樹狀圖為你展示W(wǎng)orkers之間的關(guān)系。
2.6 分支標簽
用來定義消息處理循環(huán)的分支,它是一個帶字符串輸出的VI,用來替代以往用的字符串常量,相比字符串常量更具優(yōu)勢,方便修改,查找跳轉(zhuǎn)追蹤消息流向,在Workers中提供了Quick Drop插件來自動創(chuàng)建,很實用的設計考慮。
2.7 支持使用LVOOP進行擴展
雖說Workers適合沒有LVOOP基礎的新手實用,但了解LVOOP相關(guān)知識可以更好地實用Workers框架,它采用LVOOP進行設計,提供了非面向?qū)ο?a href="http://ttokpm.com/v/tag/1315/" target="_blank">編程所不具有的一些優(yōu)點,所有的Workers都繼承自Workers.lvclass,主要的一些公共API都包含其中,框架已經(jīng)幫我們實現(xiàn)好了,大大減少了重復代碼,當開發(fā)的多個Workers有相同的行為時,可以引入中間層,新增公共方法代碼或重新Workers的公共API,這樣就可以被繼承自它的Workers使用了。
3. Worker的構(gòu)成
3.1 Worker的定義
簡單定義:模塊化的消息隊列處理程序
高級定義:一個繼承自Workers.lvclass的類,其中包含一個消息處理程序及其相關(guān)支持代碼和控件。
每個新創(chuàng)建的Worker都包含下面幾個部分:
Initialization Data.ctl:自定義簇,Worker在初始化時期望接收的任何數(shù)據(jù)的定義。
Main.vi:包含QMH的VI,也就是Worker的核心程式碼。
3.2 Workers的層次關(guān)系
典型的應用程序都是由多個Worker分層組合構(gòu)建而成,一個Worker可以在Main.vi中調(diào)用一個或多個其它的Workers,如下圖由三個Workers構(gòu)成:
Worker A:最頂層的Worker,通常稱為 "Head Worker",應用程序通過啟動它的Main.vi開始運行。它也被稱之為 Sub Worker 的 "Manager",它負責管理它的所有Sub Workers的啟動、初始化和關(guān)閉。
Worker B / Worker C:它們的Main.vi在Worker A中被調(diào)用,因而被稱作是Worker A的 "Sub Worker"。
Manager 和 Sub Worker兩個術(shù)語用來描述Workers直接調(diào)用與被調(diào)用者之間的關(guān)系。
3.3 Workers中的重要分支(框架需要,不能刪除)
3.3.1 Default
QMH中的默認分支,里面有調(diào)用一個叫Common Case.vi的VI,其中包含了所有Workers的一些公共代碼分支,框架需要用到必須存在。
3.3.2 Initialize
Worker運行起來后會第一個被執(zhí)行的分支,在該分支中會接收到它的 Manager 發(fā)送給它的一些初始化數(shù)據(jù),也就是在 Initialization Data.ctl 中定義的數(shù)據(jù)。在該分支中會調(diào)用 Write(Set) Initialization Data - Worker Name.vi 將初始化數(shù)據(jù)加載到緩存中 (如果需要的話),隨后會調(diào)用Initialize subWorkers.vi 給所有的 Sub Workers發(fā)消息執(zhí)行 “Initialize"分支,如果已經(jīng)緩存了初始化數(shù)據(jù)會一起捆綁到消息中被發(fā)送過去。
如果該Workers沒有 Sub Workers,Initialize subWorkers.vi會調(diào)用執(zhí)行 "All subWorkers Initialized" 分支。
3.3.3 All subWorkers Initialized
當所有 Sub Workers 都初始化完成時會執(zhí)行該分支(當一個Worker初始化完成時它會調(diào)用 Initialize Notify.vi 通知它的 Manager Worker),如果你想在所有 Sub Worker初始化完成后執(zhí)行某些任務,可以在該分支中進行。
3.3.4 Start Exiting
通過調(diào)用 Start Exiting Worker.vi 會執(zhí)行該分支,在該分支中會調(diào)用 Start Exiting subWorkers.vi 通知所有 Sub Workers 執(zhí)行 ”Start Exiting“ 分支開始退出操作。
如果該Workers沒有 Sub Workers,Start Exiting subWorkers.vi 會調(diào)用執(zhí)行 "All subWorkers Exited" 分支。
3.3.5 All subWorkers Exited
當所有的 Sub Worker都成功退出時,框架會自動執(zhí)行該分支(當一個Worker結(jié)束運行是它會調(diào)用 Exited Notify and Cleanup.vi 通知它的 Manager Worker),如果你想在所有 Sub Worker都結(jié)束后執(zhí)行某些任務,可以在該分支中進行。
當你想退出Worker停止運行時,需要調(diào)用 Exit.vi (stop loop? 會賦值 True),它會引起 MHL (和 EHL ,如果有的話) 的結(jié)束,從而結(jié)束Worker的運行。
3.4 初始化和退出的時序
通過一個包含4個Workers的簡單應用來進行說明。
3.4.1 初始化時序
應用程序的初始化通常是從 Head Worker 的 “Initialize” 分支執(zhí)行開始。整個初始化過程大致如下:
通過 Launcher VI 啟動 Worker A。
Worker A執(zhí)行 “Initialize” 分支,然后調(diào)用 Initialize subWorkers.vi。
所有Worker A的 Sub Worker 都執(zhí)行 “Initialize” 分支,然后它們分別調(diào)用 Initialized Notify.vi 通知 Worker A它們已經(jīng)完成初始化。
Worker A 接著就會執(zhí)行 “All subWorkers Initialized" 分支,最后它也會調(diào)用 Initialized Notify.vi 告知框架自己已經(jīng)完成初始化。
3.4.2 退出時序
應用程序的退出通常是從 Head Worker 的 “Start Exiting’” 分支執(zhí)行開始。整個初始化過程大致如下:
在Worker A中,用戶通過調(diào)用 Start Exiting Worker.vi 開始執(zhí)行退出操作,如在EHL的 "Panel Close?" 分支中調(diào)用。
Worker A執(zhí)行 “Start Exiting” 分支,然后調(diào)用 Start Exiting subWorkers.vi。
所有Worker A的 Sub Worker 都執(zhí)行 “Start Exiting” 分支,然后它們退出時分別調(diào)用 Exited Notify and Cleanup.vi 通知 Worker A它們已經(jīng)退出停止運行。
Worker A 接著就會執(zhí)行 “All subWorkers Exited" 分支,最后它也會調(diào)用 Exited Notify and Cleanup.vi 告知框架自己也已經(jīng)退出停止運行。
4. Workers中的消息
Workers中使用了兩種類型的消息,標準消息(異步)和回調(diào)消息(異步或同步)。
4.1 標準消息
標準消息是異步的,可以通過使用Enqueue Standard Message.vi來進行發(fā)送。該VI是一個多態(tài)VI,包括兩種可選的VI:
Enqueue Message to Self v2.vi
給當前的worker自己發(fā)送消息。
Enqueue Message to Queue.vi
給指定隊列的Worker發(fā)送消息。
4.2 回調(diào)消息
接收方Worker在收到消息后,可以直接向發(fā)送方Worker發(fā)送回復消息,而無需訪問其隊列。
框架中支持兩種類型的回調(diào)消息,通過調(diào)用Enqueue Callback Message.vi來進行發(fā)送,該VI是一個多態(tài)VI,包含四種可選的VI:
Enqueue and Collect.vi(同步)
給指定隊列的Worker發(fā)送同步的”Callback“消息,該線程想被掛起直到收到接收方Worker回復的 ”Callback Reply“消息或超時(默認5000ms)。
Enqueue and Collect - Silent Mode.vi (靜默模式)
Enqueue and Forget.vi(異步)
給指定隊列的Worker發(fā)送異步的”Callback“消息。
Enqueue and Forget - Silent Mode.vi (靜默模式)
通過Get Callback Message.vi找到回調(diào)消息并保存,然后調(diào)用 Callback Reply.vi給發(fā)送方Worker發(fā)送回復消息,框架中提供了Callback Easy Reply.vi方法直接使用。
4.3 靜默模式
上述消息入隊列VI都支持靜默模式(帶有靜音的圖標),功能上沒有區(qū)別,只是使用該模式發(fā)送的消息不會記錄到調(diào)試器的消息日志中,當你不想調(diào)試器被一些重復且頻繁發(fā)送的消息填滿時,使用該模式將會很有用。
4.4 消息的構(gòu)成
每條消息都包含一些特定的數(shù)據(jù)類型,它們會打包在一起進行發(fā)送,如下所示:
其中包括:
Case Lable
指定接收方Worker的MHL中分支名稱,通過Quick Drop 進行創(chuàng)建。
Data(Optional)
將任意數(shù)據(jù)類型轉(zhuǎn)成變體進行發(fā)送,接收方需要按照指定的類型進行轉(zhuǎn)換,可選。
Auxiliary(Optional)
作為附加數(shù)據(jù)進行發(fā)送,與Data類似,可選。
MetaData(hidden)
框架自身需要用到的一些數(shù)據(jù),用來標識消息的發(fā)送方和接收方,這些數(shù)據(jù)會被發(fā)送到調(diào)試器中。
4.5 消息優(yōu)先級
框架中設計的初始化和退出時序中使用的消息優(yōu)先級是“Critical”,該優(yōu)先級不對開發(fā)人員開發(fā),原因就是當Worker的消息隊列過載時,框架仍然能夠搶占消息并關(guān)閉應用程序,從而提高程序的可靠性及性能。
4.6 Case Label
創(chuàng)建Case Label
確保Worker的Main.vi程序框圖窗口處于激活狀態(tài),并將MHL中的條件分支切換到對應的分支,比如“Inset to Main Panel"。
2. 激活Quick Drop,按Ctrl + 9進行創(chuàng)建。
分支跳轉(zhuǎn)
選中要跳轉(zhuǎn)的Case Label。
激活Quick Drop,按Ctrl + 8,將會自動跳轉(zhuǎn)到對應的條件分支中。
5. Worker的加載
一個Worker可以以靜態(tài)或動態(tài)兩種方式被另一個Worker進行加載。
5.1 靜態(tài)加載
大部分時候,通過腳本工具 “Create/Add Worker" 創(chuàng)建或添加的 Sub Worker會自動以靜態(tài)的方式在 Manager Worker中進行加載。靜態(tài)加載是用得最多的方式。
5.2 動態(tài)加載
有時你期望通過編程的方式加載一些沒有事先指定的Worker,那么使用動態(tài)加載會很有用,框架中提供了Dynamically Load Worker.vi來實現(xiàn)該功能,一旦Worker被動態(tài)加載,它會自動集成到Manager Worker中,其行為方式將于靜態(tài)加載的Worker一致。
6. Workers中的調(diào)試器
Workers調(diào)試器在使用該框架開發(fā)的應用程序中扮演著不可或缺的一部分。不論一個框架多么好用,如果它創(chuàng)建的代碼難以導航和調(diào)試,那么框架帶來的高效性將大打折扣。調(diào)試器必須在Workers應用程序運行之前啟動,可以直接通過菜單 “Tools >> Workers tools...”啟動,或以編程的方式通過調(diào)用Debugger Loader.vi進行加載。
6.1 Task Manager
在Task Manager頁面可以看到所有加載的Workers層級列表,并行能看到它們的Clone ID (Workers的Main.vi是共享副本的) 和狀態(tài)。
框架中定義的一些狀態(tài)有:
Queue Created
在Manager Worker中調(diào)用執(zhí)行Setup subWorkers.vi 已經(jīng)完成了Worker的消息隊列創(chuàng)建(或是在Head Worker中調(diào)用 Setup Head Worker.vi完成了Head Worker的消息隊列創(chuàng)建)。
Pre-initialized
Worker的Main.vi已經(jīng)被加載,而且能將收到的消息出隊列,處于初始化前的一個就緒狀態(tài)。
Initialized called
Worker已經(jīng)跳轉(zhuǎn)到“Initialize”分支執(zhí)行。
Initialized
Worker已經(jīng)通過調(diào)用Initialized Notify.vi告知它的Manager Worker自己已經(jīng)完成了初始化。
Start Exiting called
Worker已經(jīng)跳轉(zhuǎn)“Start Exiting”分支開始執(zhí)行(通過調(diào)用Start Exiting Worker.vi或是在Manager Worker中調(diào)用Start Exiting subWorkers.vi.)。
Exited
The Worker已經(jīng)通過調(diào)用Exited Notify and Cleanup.vi告知它的Manager Worker自己已經(jīng)成功退出。
Stopped (Critical Error)
Worker中已經(jīng)發(fā)生了嚴重的錯誤,Worker已經(jīng)停止且不能再被訪問。
(Aborted)
當應用程序提前終止時,追加到上述狀態(tài)的字符串。
6.2 Task Manager的右鍵菜單
Open Running VI
會顯示當前正在運行的Workers的 Main.vi副本程序框圖,如果該VI不再運行,那么將打開可編輯模式的Main.vi。
Filter as Enque Worker
右鍵選中的Worker作為 Enque Worker對Message Log頁面中的信息進行過濾顯示。
Filter as Deque Worker
右鍵選中的Worker作為 Deque Worker對Message Log頁面中的信息進行過濾顯示。
6.3 Message Log
每當一條消息在Worker中出隊列時,消息中的MetaData都會被發(fā)送到調(diào)試器中記錄,在該頁面提供了以下功能:
按照時間先后順序顯示MHL之間的消息流向。
顯示應用程序中的錯誤,并告知發(fā)送的時間和位置。
允許用戶直接跳轉(zhuǎn)到Message Log中顯示的任何Worker的條件分支中。
Enque Worker
發(fā)生消息的Worker的ID。
Enque Case
Worker中發(fā)送消息的分支。
Deque Worker
接收消息的Worker的ID。
Deque Case
Worker中接收消息的分支。
Message
一個字符串可以作為消息發(fā)送到調(diào)試器中. 消息被發(fā)送到調(diào)試器中有以下方式:
用戶通過調(diào)用 Send Debugger Message.vi 進行發(fā)送。(在Workers的函數(shù)選板中可以找到)。
當框架運行時發(fā)生了錯誤,被Error Handler.vi檢測到時框架會自動發(fā)送到調(diào)試器。
6.4 Message Log的右鍵菜單
Filter String (Double Click)
該列會通過單元格中的字符串進行過濾,或在指定的單元格進行雙擊即可執(zhí)行相同的操作。
Open Running VI
顯示當前正常運行的Worker’s Main.vi (clone) 的程序框圖。
Go to Case
會跳轉(zhuǎn)到Workers編輯模式的Main.vi中特定分支,由鼠標單擊時的單元格中分支名稱決定。(該操作對Worker中的基本分支無效)
7. Workers Tools
Tools >> Workers tools...
Create/Add Worker
添加Sub Worker
Worker層級視圖
Worker的調(diào)試器界面
8. Workers Demo
產(chǎn)品老化測試,10個槽并行測試,記錄老化過程中的溫度、電壓和電流,每個槽的數(shù)據(jù)需在界面中顯示,并保存所有老化數(shù)據(jù),支持數(shù)據(jù)按時間和槽進行查詢。
審核編輯:劉清
-
LabVIEW
+關(guān)注
關(guān)注
1961文章
3651瀏覽量
322013 -
API
+關(guān)注
關(guān)注
2文章
1472瀏覽量
61750 -
調(diào)試器
+關(guān)注
關(guān)注
1文章
300瀏覽量
23668
原文標題:Workers框架入門教程
文章出處:【微信號:LabVIEW QT 修煉之路,微信公眾號:LabVIEW QT 修煉之路】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論