windows下基於Python的定時服務程式
寫在前面
假設你在閱讀本文時,已經具有了在windows平臺安裝Python以及Python第三方模組的能力。
Linux平臺下面有crontab可以做系統的定時任務, windows下也有對應的定時任務。之前做一個專案,通過windows的計劃任務呼叫php指令碼定時給滿足條件的使用者傳送郵件,但是定時任務執行的很不穩定,且針對每個任務都需要做一個單獨的定時器,配置比較麻煩,還容易出錯。於是就想到了用Python指令碼做一個服務程式用來執行定時任務。
做Python定時服務程式首先要解決一下幾個問題
1 如何用Python編寫windows服務程式?
2 如何定義定時任務?(本文借鑑Linux的crontab,進行定時任務的定義)
3 如何實現通用?(web開發中需要執行定時任務的需求也比較多)
4 如何脫離Python環境單獨執行?(用pyinstaller打包exe)
下面從上面4個方面講述以下我的Python定時服務程式的實現過程,文後附實現的程式碼。
基於Python的windows 服務程式的編寫
用Python來做windows服務程式必須要藉助第三方模組pywin32,可以通過pip安裝。先上程式碼,
#!/usr/bin/python
# -*- coding: utf8 -*-
import win32service
import win32serviceutil
import win32event
import servicemanager
import os, sys, time
from smco_croniter import SMCOSched
class CronDaemon(win32serviceutil.ServiceFramework):
# you can NET START/STOP the service by the following name
_svc_name_ = "Cron Daemon"
# this text shows up as the service name in the Service
# Control Manager (SCM)
_svc_display_name_ = "Cron Daemon"
# this text shows up as the description in the SCM
_svc_description_ = "Cron Daemon for scheduled tasks"
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self,args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.isAlive = True
def SvcDoRun(self):
while self.isAlive:
print "your code"
time.sleep(10)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
self.isAlive = False
if __name__ == "__main__":
if len(sys.argv) == 1:
try:
evtsrc_dll = os.path.abspath(servicemanager.__file__)
servicemanager.PrepareToHostSingle(CronDaemon)
servicemanager.Initialize('CronDaemon', evtsrc_dll)
servicemanager.StartServiceCtrlDispatcher()
except win32service.error, details:
if details[0] == winerror.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
win32serviceutil.usage()
else:
win32serviceutil.HandleCommandLine(CronDaemon)
用Python實現windows服務程式還是比較簡單的,只需要繼承win32serviceutil.ServiceFramework 類即可,而我們需要做的就是在繼承的類中呼叫我們需要定時執行的程式碼。上面的程式碼在網上有很多,幾乎成為了一個模板,這裡不再深入的講述。
如何定義定時任務?
windows上的定時任務配置比較麻煩,而Linux的cron實現的定時任務就比較簡單,只需要配置執行的時間和命令即可,基本格式如下(詳情請參考,Linux定時任務)
分 時 天 月 周 命令
每分鐘執行一次,可以寫成, */1 * * * * cmd
每天上午8點執行一次, 可以寫成,0 8 */1 * * cmd
因此,我們可以利用linux的cron 定義計劃任務。那如何解析cron的計劃呢?很幸運,Python已經提供了這個模組,croniter,我們使用 pip install croniter即可安裝croniter模組。
至此,就可以利用croniter解析Linux cron格式的計劃任務了,而我們只需將計劃任務寫入到檔案中,再有Python讀取即可。我定義的計劃任務格式如下:
croniter的使用方法如下:
croniter.croniter(sched,basetime)
只需要傳入計劃任務sched,和計劃的開始時間,就可以計算出下一次需要執行的時間,如執行
croniter.croniter("*/5 * * * *","2017-01-04 19:43")
那麼計算出的定時任務的下一次執行時間就是,2017-01-04 19:48
如何實現通用?
本文類之間的關係如下圖所示,
很慚愧,在我的程式碼中並沒有實現通用,這裡我提供一個重構的思路,歡迎大家來一起討論。
我的思路是將任務抽象成一個介面TaskInterface,以後每新增一個新的定時任務,直接繼承TaskInterface,並實現介面中的方法即可。
如何脫離Python環境單獨執行?
這個問題比較容易解決,使用PyInstaller,將Python的程式打包成一個exe即可,然後就可以在沒有安裝Python的環境中運行了。