寫在前面
假設你在閱讀本文時,已經具有了在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的環境中運行了。
也可以參考一下我的這篇博客,http://blog.csdn.net/guoxiaojie_415/article/details/50988943
源碼下載地址:http://download.csdn.net/detail/guoxiaojie_415/9729020