python定時任務


一個簡單的需求,即定時啟動python腳本,這種需求很常見,比如定時啟動一段程序對服務器狀態進行收集,寫到文件中,方便運維后期審計,查看服務器占用高峰時間段,從而判斷出公司產品在該時間段較多人使用,或定時清除其他程序的日志,釋放線上服務器的空間,這塊常見的架構是有個轉存程序,將日志通過nginx文件服務掛起,然后該程序請求這種文件,將其存儲在數據服務器中,而線上服務器的日志就不需要了(游戲日志通常比較大,所以轉存程序也需要設計一下)。

本章主要來實現一下定時啟動python的需求,當然,定時啟動其他任何程序也都一樣。

Python threading模塊

一開始,為了省事,直接使用python的threading模塊,threading模塊下有個Timer模塊,它可以實現定時啟動python程序的需求,用法如下:

  1. from threading import Timer

  2. def timedTask():

  3. ? ?print(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))

  4. ? ?main() #主題程序邏輯

  5. ? ?global timer

  6. ? ?timer = Timer(300,timedTask)

  7. ? ?timer.start()


  8. if __name__ == '__main__':

  9. ? ?timedTask()

值得一提的是,timer需要使用global timer,據說嘗試運行時,會釋放無需使用的占用資源。

實現方法很簡單,即創建Timer()實例,傳入兩個參數,分別是時間間隔(單位為秒)與定時任務本身,構成一個死遞歸(因為沒有逃出條件),然后就是調用Timer實例的start()方法。

不推薦,雖然網上博客說使用global timer會釋放無用資源,但實際沒有考證,這種寫法在服務器上跑起來的程序通常一天就斷,我周日啟動該程序,周一來公司看,對應的python程序掛了。

APScheduler

APScheduler是Python用于執行定時操作的第三方框架,作為一個框架,它就有它對應的各種概念,沒必要搞那么復雜,學習成本有點高,放棄

Linux crontab

最總還是轉到了Linux的crontab服務,該服務主要就是用于實現定時任務的,其語法如下:

  1. # .---------------- minute (0 - 59)

  2. # | ?.------------- hour (0 - 23)

  3. # | ?| ?.---------- day of month (1 - 31)

  4. # | ?| ?| ?.------- month (1 - 12) OR jan,feb,mar,apr ...

  5. # | ?| ?| ?| ?.---- day of week (0 - 6) (Sunday=0 or 7) ?OR

  6. #sun,mon,tue,wed,thu,fri,sat

  7. # | ?| ?| ?| ?|

  8. # * ?* ?* ?* ?* ?command to be executed

  • minute:代表一小時內的第幾分,范圍 0-59。

  • hour:代表一天中的第幾小時,范圍 0-23。

  • mday:代表一個月中的第幾天,范圍 1-31。

  • month:代表一年中第幾個月,范圍 1-12。

  • wday:代表星期幾,范圍 0-7 (0及7都是星期天)。

  • who:要使用什么身份執行該指令,當您使用 crontab -e 時,不必加此字段。

  • command:所要執行的指令。

  • crontab服務狀態

    1. sudo service crond start ? ? #啟動服務

    2. sudo service crond stop ? ? ?#關閉服務

    3. sudo service crond restart ? #重啟服務

    4. sudo service crond reload ? ?#重新載入配置

    5. sudo service crond status ? ?#查看服務狀態

    查看定時任務

    1. crontab -l

    到這里,關于crontab常見的文件就是叫你使用 crontab-e來編寫對應crontab配置文件,配置內容的語法如上,例子如下:

    1. # 每天早上6點

    2. 0 6 * * * echo "Good morning." >> /tmp/test.txt //注意單純echo,從屏幕上看不到任何輸出,因為cron把任何輸出都email到root的信箱了。


    3. # 每兩個小時

    4. 0 */2 * * * echo "Have a break now." >> /tmp/test.txt ?


    5. # 晚上11點到早上8點之間每兩個小時和早上八點

    6. 0 23-7/2,8 * * * echo "Have a good dream" >> /tmp/test.txt

    但這邊不會這樣操作,這種寫法并不適合于真正的工作中,就是一個Toy,我希望的是全自動化,這里通過shell腳本來實現自動添加crontab任務。

    shell腳本代碼如下:

    1. #! /bin/bash


    2. cd LogSys/

    3. work_path=/x1_game/agent_flask/LogSys/


    4. if [ ! -n "$1" ]; then

    5. ? ?echo "Usages: sh startLog.sh [start|stop]"

    6. ? ?exit 0

    7. fi


    8. if [ "$1" = start ] ;then

    9. ? ?if [ ! -x logs ] ;then

    10. ? ? ? ?mkdir logs

    11. ? ?fi

    12. ? ?if [ -f logs/logsys.ini ] ;then

    13. ? ? ? ?echo "logsys task is in crontab, can not add the task to crontab agent!"

    14. ? ? ? ?exit 0

    15. ? ?else

    16. ? ? ? ?echo $(date "+%Y_%m_%d") >> logs/logsys.ini

    17. ? ? ? ?chmod 777 start.sh

    18. ? ? ? ?echo "* * * * * ${work_path}start.sh start >> ${work_path}logs/cron.log 2>&1" >> /var/spool/cron/root

    19. ? ? ? ?echo "add LogSys task to crontab"

    20. ? ?fi


    21. elif [ "$1" = stop ] ;then

    22. ? ?if [ -f logs/logsys.ini ] ;then

    23. ? ? ? ?rm -rf logs/logsys.ini

    24. ? ? ? ?rm -rf /var/spool/cron/root

    25. ? ? ? ?echo "Stop success and remove the logsys.ini"

    26. ? ?else

    27. ? ? ? ?echo "logsys is not running"

    28. ? ?fi

    29. fi

    這是我使用的完整shell腳本,這里自動添加crontab任務的命令只有一行,就是 echo"* * * * * ${work_path}start.sh start >> ${work_path}logs/cron.log 2>&1">>/var/spool/cron/root,這個命令會每分鐘都會調用start.sh腳本,而start.sh腳本中啟動了python,幾個坑需要注意,crontab中請使用絕對路徑,因為crontab啟動程序時,相對路徑所對應的坐標系其實與你手動啟動該腳本時是不同的,使用絕對路徑省事,這里還將star.sh腳本的輸出內容都重定向到對應的日志文件中。

    為什么不直接通過crontab啟動python程序呢?而是要再繞一層,通過shell腳本來啟動,這其實也是一個坑,除非你是單python文件,不然通常都使用shell腳本的形式啟動python,而不在直接使用crontab來啟動,這同樣是因為crontab啟動的任務相對路徑的坐標系改變了,多文件的python項目相互引入文件時,使用的坐標系與crontab啟動時不同,導致crontab直接啟動python項目會失敗,所以技巧就在于,通過shell腳本來啟動python程序,在啟動前,通過cd命令進入python項目對應的目錄,這樣就將啟動時的相對路徑的坐標系改成與python的一致了

    具體可以看一下我的start.sh腳本,代碼如下:

    1. #! /bin/bash


    2. currTime=$(date "+%Y_%m_%d")

    3. logfile=${currTime}_logsys.log


    4. if [ ! -n "$1" ]; then

    5. ? ?echo "Usages: sh start.sh [start|stop]"

    6. ? ?exit 0

    7. fi


    8. if [ ! -x logs ] ;then

    9. ? ?mkdir logs

    10. fi


    11. pid=`ps -ef | grep log2mysql | grep -v grep|awk '{print $2}'`


    12. if [ "$1" = start ] ;then

    13. ? ?if [ -n "$pid" ] ;then

    14. ? ? ? ?echo "log2mysql is running, can not start"

    15. ? ? ? ?exit 0

    16. ? ?fi

    17. ? ?cd /x1_game/agent_flask/LogSys/

    18. ? ?nohup /usr/local/bin/python -u log2mysql.py >> logs/$logfile 2>&1 &

    19. ? ?pid=`ps -ef | grep log2mysql | grep -v grep|awk '{print $2}'`

    20. ? ?echo "start log2mysql, pid is:"$pid

    21. elif [ "$1" = stop ] ;then

    22. ? ?if [ -n "$pid" ] ;then

    23. ? ? ? ?echo "kill log2mysql, pid is: "$pid

    24. ? ? ? ?kill -9 $pid

    25. ? ?else

    26. ? ? ? ?echo "log2mysql is not running "$pid

    27. ? ?fi

    28. fi

    通過python啟動任務的關鍵命令在于

    1. cd /x1_game/agent_flask/LogSys/

    2. nohup /usr/local/bin/python -u log2mysql.py >> logs/$logfile 2>&1 &

    首先會進入要啟動python項目的所在目錄,然后再通過python啟動對應的py文件,這里使用python解釋器同樣要使用全路徑,因為線上系統中存在多個python,因為該python程序是耗時程序,所以我希望它在后臺運行,所以使用了 nohup&關鍵字,將其放在后臺去運行。

    題外話:centos系統中的yum是依賴python的,具體到centos6,其yum依賴系統本身就存在的python2.6,但開發環境通常要使用python2.7,此時最好不要刪除系統中自帶的python2.6,如果你直接刪除,會導致yum使用不了,此時就需要修改一下yum對應文件中的python指向,最好的方法就是直接安裝python2.7,然后在/usr/bin下創建對應的軟連接來使用。

    小結

    python程序員在工作中其實不能只會python,因為python雖然強大,但也會有其缺陷,所以什么好用,用什么才是對的,還有python是一種語言,不要被語言局限。

    ?著作權歸作者所有,轉載或內容合作請聯系作者
    • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
      沈念sama閱讀 227,572評論 6 531
    • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
      沈念sama閱讀 98,071評論 3 414
    • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
      開封第一講書人閱讀 175,409評論 0 373
    • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
      開封第一講書人閱讀 62,569評論 1 307
    • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
      茶點故事閱讀 71,360評論 6 404
    • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
      開封第一講書人閱讀 54,895評論 1 321
    • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
      沈念sama閱讀 42,979評論 3 440
    • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
      開封第一講書人閱讀 42,123評論 0 286
    • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
      沈念sama閱讀 48,643評論 1 333
    • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
      茶點故事閱讀 40,559評論 3 354
    • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
      茶點故事閱讀 42,742評論 1 369
    • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
      沈念sama閱讀 38,250評論 5 356
    • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
      茶點故事閱讀 43,981評論 3 346
    • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
      開封第一講書人閱讀 34,363評論 0 25
    • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
      開封第一講書人閱讀 35,622評論 1 280
    • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
      沈念sama閱讀 51,354評論 3 390
    • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
      茶點故事閱讀 47,707評論 2 370

    推薦閱讀更多精彩內容