2008年3月26日 星期三

PB單線式自動排程設計(一)

簡介:
這裡所謂單線式排程程式,意指排程掃描與工作處理程式都寫在同一支程式裡面,由於PowerBuild 6程式本身無法像C#般寫成多執行緒的能力,因此在同時處理許多作業時,都得依照程式碼執行的STACK順序執行,故名為"單線式"

準備與設計:
1.首先必須要有一分工作排程清單,例如每日工作

這樣的資料表結構你可以設計成DataWindow,當然你如果要增加欄位或是功能,都是可以的,不過基本上的結構是如此。

結構中"時"、"分"的欄位是用來比對是否進行工作的時間點,當時間行程到達該時間點時就得進行該工作的執行。

"執行時間"則是代表此工作"被執行完成"的時間點,這個用來判斷該工作是否已經被執行,而不會被重複執行的要件。

"啟用"則是決定該工作是否需要被執行,有的人會以另一種觀點"暫停"來設計。

"工作名稱"顧名思義只是用來顯示的名稱,讓人一目瞭然知道此工作的用途。

"代號"則是代表該工作在程式碼運作時的實際作業。

2.設計視窗:
設計一個window(w_app),並將上述排程DataWindow(dw_1)加入裡面。











另外設計一個MultiLineEdit,用以觀察執行結果。

3.程式碼撰寫:
OPEN事件
由於排單位是以"分"為基礎比對單位,故時間的區隔就以"分"為準則,因此在w_app的Open事件中寫入Timer(60),表示以60秒觸發一次Timer事件。

TIMER事件

Long    ll_count , ll_row

ll_count = dw_1.RowCount()
For ll_row = 1 to ll_count
// 檢查該工作是否啟用,若不啟用則跳過
If dw_1.GetItemString(ll_row , 'active') <> '1' Then Continue

// 檢查當天是否已經被執行過,若執行過者不再被執行
If date(dw_1.GetItemDatetime(ll_row , 'work_time')) >= today() then Continue

// 檢查是否符合執行時間,需要被執行
If dw_1.GetItemNumber(ll_row , 'hour') = Hour(now()) and &
dw_1.GetItemNumber(ll_row , 'min') = Minute(now()) then


// 填入/覆寫執行時間
dw_1.SetItem(ll_row , 'work_time' , Datetime(today() , now()))

// 顯示執行訊息
mle_1.text += String(now() , 'hh:mm') + &
' 執行工作[' + dw_1.GetItemString(ll_row , 'name') + '] ~r~n'

// 依照代號執行需要做的事情
Choose Case dw_1.GetItemString(ll_row , 'code')
Case 'A'
// 執行工作A的程式碼......
Case 'B'
// 執行工作B的程式碼......
Case 'C'
// 執行工作C的程式碼......
Case 'D'
// 執行工作D的程式碼......
Case 'E'
// 執行工作E的程式碼......
End Choose
end if

Next


4.以上只要在各執行工作的Case中寫入程式碼就完成基本的單線自動排程程式,其他的部份再依照個人需求去增減功能即可,如排程增減/維護/存檔。

優點:
原理簡單、撰寫設計容易,維護也容易,適合於資料處理量少的工作。

缺點:
每次增加工作都必須修改程式碼。
遇到單一工作處理資料量過大需要較長的工作時間時(超過1分鐘者),排程容易崩潰,使排程失效,甚而使程式CRASH掉。

程式為何會CRASH?原因出在TIMER指令,假設第一次觸發TIMER事件後執行其中一個工作A,而A工作剛好發生問題(讀資料過久、無限回圈等等),當然程式主執行緒會一直處在等待A工作完成才能繼續,但是TIMER指令是由系統CLOCK觸發,因此在每分鐘觸發一次的情況下,TIMER事件的STACK會不斷累積直到溢位,當溢位發生時程式便CRASH了。

範例程式下載

0 個回應: