2014年7月26日

股市自動交易系統(半完成品) - JavaATS程式架構 - Timer Server

這篇開始,會分幾篇來解釋目前JavaATS的程式架構,
讓有興趣修改、增加功能的網友能比較容易看懂程式。

這篇就直接切入最核心的部份,Timer Server和它相對應的Script Task List。

一開始再貼一次JavaATS程式架構圖:
這篇的重點會放在藍色字標注的區塊。

程式流程:
說得再多,比不過一張流程圖清楚,直接看流程圖:


第1張流程圖是JavaATS建構子的執行流程,
過程簡單,就是建立1個Timer定時觸發,觸發呼叫特定Method。

第2張流程圖才是關鍵所在,
當Timer觸發後,會呼叫MyTimerServerEvent這個Method,
接著它會從ScriptTasks這個List中,陸續取出所有Task來檢查和執行。

檢查時,會先判斷是否有IntervalTime(Interval模式),
如果有,就進入Interval模式。
如果沒有,就進入crontab的時間字串模式。

Interval模式:
1. 先取得上次執行的時間
2. 如果沒執行過,直接執行
3. 如果上次執行時間 + 間隔時間 >= 現在時間,表示到時或超時了,直接執行

crontab時間字串模式:
1. 先取得上次執行時間
2. 上次執行時間和現在時間同分鐘,表示執行過了
3. 週末是否設定不執行,現在是否是週末
4. 檢查現在時間是否符合crontab時間字串,符合就執行

crontab時間字串設計:
在crontab時間字串模式的設計,我一開始想了很久,
到底Linux的crontab是怎麼檢查執行的,
後來想到,Linux的crontab如果超過時間了,它是不會執行的,
我因此瞭解到它的時間檢查是反過來的。

它的核心設計是用現在時間來比較crontab時間字串是否符合。
給個簡單的例子:
假設:設定10:03分要執行 (假設時間字串為10:03)

電腦會每分鐘檢查一次現在時間,
10:00分時,時間字串為 10:00,10:00和10:03字串不符,不執行
10:01分時,時間字串為 10:01,10:01和10:03字串不符,不執行
10:02分時,時間字串為 10:02,10:02和10:03字串不符,不執行
10:03分時,時間字串為 10:03,10:03和10:03字串相符,執行

因此,它只需要每次檢查時,將現在時間轉成時間字串,
然後比較現在時間的字串是否符合Task時間的字串,
就能判斷是否執行。

當然,這裡面的字串比對比較複雜,
用傳統的indexOf或strstr或substring,那會比較到發瘋,
因此這裡是用Regular Expression,
它直接可以確定字串格式,並且把格式中所有項目的資訊一次取得,
然後各個項目比較即可。

還是以上面的10:03為例:
現在時間:Regular Expression類似(10):(02)
Task時間:Regular Expression類似(10):(03)

即可直接取得
Now[0] = 10
Now[1] = 02

TaskTime[0] = 10
TaskTime[1] = 03

接著只要Now[0]和TaskTime[0]比較,Now[1]和TaskTime[1]比較,
全部Pass,就是字串符合,這個例子中,Now[1]和TaskTime[1]不一樣,所以不執行。

延伸思考:
如果有在使用Google的Google日曆,注意到Google日曆的時間設定,
你會發現它彈性非常大,它一樣可以設定單次時間行程、週期時間行程,
但神奇的是,它定義好週期時間行程後,
還可以將週期時間行程的某幾個時間行程刪除或變更,
這樣的設計,我其實覺得滿高明的,我還沒有想通它的設計原理。

時間精確度問題:
crontab時間字串的設計有個致命傷,
因為它必須用現在時間來比較Task時間字串
因此它每次的現在時間,都必須有個緩衝空間。

假設crontab時間字串的精準度設定為
意思是,電腦必須每秒取得一次現在時間,
並且要在1秒內完成所有Task的時間字串比對,
只要電腦處理超時1秒鐘,
就會造成這秒的所有Task全部沒有執行。

文字不好表達,來個例子:

假設:
Task 1 10:00:02    定義10點00分02秒執行         執行時間0.2秒
Task 2 10:00:02    定義10點00分02秒執行         執行時間2秒
Task 3 10:00:03    定義10點00分03秒執行

以這樣有3個Task為例,
在10:00:02時,
Task 1會先執行,接著Task 2會執行。

Task 2執行完後,時間應該已經是10:00:04,
Task 3就會永遠略過不執行。

這就是為什麼crontab的時間精確度只能到的原因,
因為大部分Shell程式,很少執行時間會超過1分鐘,
crontab的說明中有稍微提到一點點,
它有提到,crontab的執行時間不能過長,否則就是建議放到背景執行。

回到JavaATS,
目前設計,我並沒有設計multi-threading,
我的假設是,Task的bsh Script執行時間,應該是不會長的太誇張,
正常網路下,一般操作的Delay,應該是不會離譜到超過1分鐘以上。

沒有留言: