主要是要實現tornado實現計劃任務類crontab間隔
大家看了標題,可能知道我要寫啥了 ~ 對頭,我用tornado實現一個類似crontab時間間隔排程的程式。
我為啥要寫這個?
一方面是 更加深入的瞭解tornado非同步方面的能力 。 另一方面是 在特殊的環境下編寫更適合更方便自己的工具。
啥特殊的環境?
比如,我們有好幾個後端指令碼,這些指令碼都要間隔的執行排程。然而這些程式都是秒級別的,這樣的話,你用crontab就不太適合了。當然你可以後臺仍個指令碼,然後sleep 也是可以的。 要是很多的話? 你執行多個指令碼?
我上個監控校驗專案——就有很多的後臺有間隔的指令碼跑著。每次系統有改變我都要kill掉程序,除錯好了,再start,挺蛋疼的~
後來我把很多的監控校驗都放到一個腳本里面,然後開多執行緒,讓他自己去sleep。以後我只需要kill掉一個程序就行了。
Python本身自帶了一個排程模組sched,timer,官方給出的例子,都是那樣,呼叫一次的用法。
任務是併發執行的,但是s.run()會把執行緒堵塞掉,所以咱們有必要把s.run()放到一個獨立的執行緒去執行。當然你要是有需要的話。
01.
&
gt
;&
gt
;&
gt
;
import
sched,
time
02.
&
gt
;&
gt
;&
gt
;
s = sched.scheduler(
time
.
time
,
time
.
sleep
)
03.
&
gt
;&
gt
;&
gt
;
def print_time(): print
"From print_time"
,
time
.
time
()
04.
...
05.
&
gt
;&
gt
;&
gt
;
def print_some_times():
06.
... print
time
.
time
()
07.
... s.enter(5, 1, print_time, ())
08.
... s.enter(10, 1, print_time, ())
09.
... s.run()
10.
... print
time
.
time
()
11.
...
12.
&
gt
;&
gt
;&
gt
;
print_some_times()
13.
930343690.257
14.
From print_time 930343695.274
15.
From print_time 930343700.273
16.
930343700.276
scheduler例項含有以下方法和屬性:
01.
scheduler.enterabs(
time
, priority, action, argument)
02.
排程一個新事件,
time
引數應該是數值型別的。
03.
scheduler.enter(delay, priority, action, argument)
04.
延遲排程一個事件,不同於相對時間
05.
scheduler.cancel(event)
06.
在事件佇列中移除一個事件,如果事件不在事件佇列中,則觸發ValueError
07.
scheduler.empty()
08.
如果事件佇列為空則返回True
09.
scheduler.run()
10.
執行所有的排程事件,該函式會等待下一個事件,然後執行他直到沒有可排程的事件為止。
11.
scheduler.queue
12.
只讀屬性,返回一個list,裡面包含了即將執行的事件列表。
需要關注的是 sched模組不是迴圈的,一次排程被執行後就完事了,如果想再執行,請再次enter事件了。
我們再來感受下sched裡面的timer !
01.
&
gt
;&
gt
;&
gt
;
import
time
02.
&
gt
;&
gt
;&
gt
;
from threading
import
Timer
03.
&
gt
;&
gt
;&
gt
;
def print_time():
04.
... print
"From print_time"
,
time
.
time
()
05.
...
06.
&
gt
;&
gt
;&
gt
;
def print_some_times():
07.
... print
time
.
time
()
08.
... Timer(5, print_time, ()).start()
09.
... Timer(10, print_time, ()).start()
10.
...
time
.
sleep
(11)
#
sleep while time-delay events execute
11.
... print
time
.
time
()
12.
...
13.
&
gt
;&
gt
;&
gt
;
print_some_times()
14.
930343690.257
15.
From print_time 930343695.274
16.
From print_time 930343700.273
17.
930343701.301
說完了後,我們這裡跑個實際中能用到的例子:
我們跑看看,我們中間加了sleep 2s ,然而他所用的時間是7s,說明他是併發執行的。
關於執行緒的timer我簡單寫了個例子,跑了下,感覺怪怪的。
01.
import
threading
02.
import
time
03.
def timer_start():
04.
t = threading.Timer(2,func,(
"xiaorui.cc"
,
"2s"
))
05.
t.start()
06.
t2 = threading.Timer(4,rui,(
"4s"
,
"nima"
))
07.
t2.start()
08.
def func(msg1,msg2):
09.
print
"come on,"
,msg1,msg2
10.
print
time
.strftime('%Y%m%d%H%M %S')
11.
timer_start()
12.
def rui(msg3,nima):
13.
print 'this is rui %s %s'%(msg3,nima)
14.
timer_start()
15.
if
__name__ ==
"__main__"
:
16.
timer_start()
17.
while
True:
18.
time
.
sleep
(1)
執行的結果,時不時的會亂,這東西不太適合做crontab的效果。
我這裡微微的總結下:
按照我的測試,sched和timer不適合做迴圈的計劃任務,當然你可以在sched呼叫函式的時候,用while sleep的方法實現也是靠譜的。。。。
感覺python應該有靠譜點的計劃任務模組,問了下朋友,他們現在用的是 APScheduler
一個很牛逼的庫~ 已經測試過了
特定時間的執行:
1.
from apscheduler.scheduler
import
Scheduler
2.
sched = Scheduler()
3.
sched.daemonic = False
4.
def job_function(text):
5.
print text
6.
from datetime
import
datetime
7.
job = sched.add_date_job(job_function, datetime(2013, 10, 11, 02, 36, 00), ['Hello World'])
8.
sched.start()
間隔的執行:
01.
from apscheduler.scheduler
import
Scheduler
02.
import
time
03.
sched = Scheduler()
04.
sched.daemonic = False
05.
def job_function():
06.
print
"wan si ni"
07.
print
time
.strftime('%Y%m%d%H%M %S')
08.
sched.add_interval_job(job_function, seconds=3)
09.
sched.start()
迴圈3s,ok !!!
哈,我簡單說了下 python下實現計劃任務的幾種方式,本來要聊tornado,結果搞到標準庫了。
暈,趕緊說正題:
python的web框架中tornado是強大的,他的IOLoop類是Tornado的邊緣觸發事件驅動模型,在Linux平臺下面封裝的是epoll模型。這就是他的非同步模式的基礎。
要是合成到tornado的ioloop的話,我啟動一個主程式,不僅把相應的指令碼按照間隔排程跑起來,主web也可以訪問啦。
用python實現計劃任務,除了python自帶的shed,timer之外,我能想到的就是開多執行緒,自己去處理每個任務以及時間間隔。還有就是tornado的ioloop。
精力有限,現在還沒有做出像linux系統下的crontab那樣的工具。
我想到的思路是 配置檔案可以就是crontab的時間語法,或者是咱們用yaml,configparser。程式啟動的時候,開一個執行緒,專門關注這些個資料,對於任務和時間都要採用全域性的變數,這些個函式進入主體的時候,先把global變數載入進來,然後大家就懂啦。。。。
下面是我用tornado ioloop實現的方法:
01.
from tornado
import
web, ioloop
02.
import
datetime
03.
period = 5 * 1000
# every 5 s
04.
class MainHandler(web.RequestHandler):
05.
def get(self):
06.
self.write('Hello Tornado')
07.
def like_cron():
08.
print datetime.datetime.now()
09.
def xiaorui():
10.
print 'xiaorui 2s'
11.
def lee():
12.
print 'lee 3s'
13.
14.
if
__name__ == '__main__':
15.
application = web.Application([
16.
(r'/', MainHandler),
17.
])
18.
application.listen(8081)
19.
ioloop.PeriodicCallback(like_cron, period).start()
# start scheduler
20.
ioloop.PeriodicCallback(lee, 3000).start()
# start scheduler
21.
ioloop.IOLoop.instance().start()
結果:
再跑計劃任務的時候,不影響web的訪問
一眨眼,發現自己原本要寫tornado,結果成大雜燴了~
微微總結下這幾種計劃任務的方法:
sched 就原版的例子來說,不適合做迴圈執行的,就單個計劃任務是挺不錯的。要是想做迴圈,不要讓那個執行緒死掉,一直while True: 就行了
timer 同sched,不知道為啥多工的時候,出現奇怪的問題。。。
apscheduler 這個是利器,好用,也是必須推薦使用的。
tornado 我自己覺得是很不錯的,他和別的方法不一樣,別人是執行緒,他是非同步回撥的方式,他背靠著epoll非同步,所以很爽。
自己寫 這個實現的思路,其實和sched timer,差不多的,我也有提過,就是個多執行緒,然後while True
轉自:http://www.it165.net/os/html/201310/6453.html