最近做了幾個PHP的遊戲項目,有棋牌遊戲也有rpg遊戲,其中都或多或少的需要一些定時更新資訊的機制。比如棋牌遊戲的玩家逾時檢測。rpg遊戲中用到的就更多了,怪物重新整理、自動回血、任務到期、熱門排行榜重新整理等等。因為PHP沒有記憶體駐留程式,所以在處理上有一些困難。
我參考了一些同行的實現方法,通常的做法是根據具體項目的需要,用c++、python、java等寫一個輔助程式,定時對資料庫進行更新。但是這樣做很麻煩。首先,這些輔助程式需要懂另外一門語言的程式員介入,勢必會增加一定開發成本和風險。第二,不同語言程式員之間聯調很麻煩,進度很慢,由於輔助程式與前台之間的關係很緊密,基本上需要同時開發,一起調試。
我在項目中採用了一種定時執行任務的方法,自己感覺這個方案比較好,屬於一勞永逸型的,把所有代碼全都交給PHP這邊。
首先在資料庫中,定義一個名為task的表,裡面有兩個欄位 exectime 和 url。其中exectime是一個unix類型的時間,url是字串型的。每條資料都代表一個任務,具體意義是“這條任務在exectime時執行,執行的地址為url”。輔助程式會每隔一秒鐘監視一次這個表,把目前時間對比表中每個任務的時間,如果時間達到,則請求該url,而後任務執行完成,刪除這條任務。如此迴圈往複。
這樣做的好處是PHP程式開發人員可以很自由的在他們想要的時間執行他們想要執行的網頁。而且這個程式只需要寫一次,放到任何類似項目中都可以很好的使用。
我將這個程式做成了windows服務和archlinux的Daemon,這樣就實現了整個項目的跨平台。
補充內容:
任務的開啟是這樣的,我們做了一個類似大型網遊的伺服器開關介面,登入遊戲後台後,到伺服器控制頁面,可以查看當前伺服器的運行狀態,可以開啟或者關閉伺服器。開啟伺服器則是把相關任務插入到工作清單中,關閉伺服器是把工作清單清空。是人工形式的。
任務的重複開啟,因為這些任務都是由php插入到任務表中去的,而且任務表中的每條任務都是執行一次就由輔助程式刪除的,所以每個任務只能執行一次。如果有任務需要迴圈執行,那麼就只能是通過在執行這個任務(即任務的url)的php代碼裡面,再把他自己重新插入到工作清單中去。
任務的逾時,任務逾時分為兩種,資料表中,任務的執行之間逾時,一種是請求該任務頁面逾時。第一種情況不會發生,因為輔助程式每次都執行小於等於目前時間的所有任務。第二種情況,輔助程式會自動判斷這個頁面的訪問是否成功,如果返回伺服器錯誤或無法串連等,就保留此任務,不刪除,等到下次迴圈時再嘗試執行。