Python 自帶的優先級調度器

攝影:產品經理

幸福感的來源

Python 自帶一個調度器模塊sched,它能爲你實現優先級隊列 / 延遲隊列和定時隊列。

這個模塊的使用非常簡單,首先以延遲隊列爲例:

import sched

def do_work(name):
    print(f'你好:{name}')

sch = sched.scheduler()
sch.enter(5, 1, do_work, argument=('kingname'))
sch.run()

代碼運行以後,會卡在sch.run()這裏,5 秒鐘以後執行do_work('kingname'),運行效果如下圖所示:

其中,sch.enter()的第一個參數爲延遲的時間,單位爲秒,第二個參數爲優先級,數字越小優先級越高。當兩個任務同時要執行時,優先級高的先執行。但需要注意的是,如果你這樣寫:

import sched

def do_work(name):
    print(f'你好:{name}')

sch = sched.scheduler()
sch.enter(5, 2, do_work, argument=('產品經理'))
sch.enter(5, 1, do_work, argument=('kingname'))
sch.run()

那麼先打印出來的是你好:產品經理,如下圖所示:

爲什麼這裏優先級失效了?1 的優先級大於 2,應該先運行下面的纔對啊。

這是由於,只有當兩個任務同時運行的時候,纔會去檢查優先級。如果兩個任務觸發的時間一前一後,那麼還輪不到比較優先級。由於延遲隊列的延遲是相對於當前運行這一行代碼的時間來計算的,後一行代碼比前一行代碼晚了幾毫秒,所以實際上產品經理這一行會先到時間,所以就會先運行。

爲了使用絕對的精確時間,我們可以使用另外一個方法:

import sched
import time
import datetime

def do_work(name):
    print(f'你好:{name}')

sch = sched.scheduler(time.time, time.sleep)
start_time = datetime.datetime.now() + datetime.timedelta(seconds=10)
start_time_ts = start_time.timestamp()
sch.enterabs(start_time_ts, 2, do_work, argument=('產品經理'))
sch.enterabs(start_time_ts, 1, do_work, argument=('kingname'))
sch.run()

運行效果如下圖所示:

sch.enterabs()的第一個參數是任務開始時間的時間戳,這是一個絕對時間,這個時間可以使用 datetime 模塊來生成,或者其他你熟悉的方式。後面的參數和sch.enter()完全一樣。

如果你要運行的函數帶有多個參數或者默認參數,那麼可以使用下面的方式傳入參數:

import sched
import time
import datetime

def do_work(name, place, work='寫代碼'):
    print(f'你好:{name},你在:{place}{work}')

sch = sched.scheduler(time.time, time.sleep)
start_time = datetime.datetime.now() + datetime.timedelta(seconds=10)
start_time_ts = start_time.timestamp()
sch.enter(5, 2, do_work, argument=('產品經理''杭州')kwargs={'work''寫需求文檔'})
sch.enterabs(start_time_ts, 1, do_work, argument=('kingname''產品經理旁邊')kwargs={'work''看着她'})
sch.run()

argument 參數對應的元組存放普通參數,kwargs 對應的字典存放帶參數名的參數。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/-bSEyuH1eUyiQKu6rraV1Q