無所不能的Python竟然沒有一個像樣的定時器?試試這個!

      網友投稿 1447 2025-04-01

      所謂定時器,是指間隔特定時間執行特定任務的機制。幾乎所有的編程語言,都有定時器的實現。比如,Java有util.Timer和util.TimerTask,javaScript有setInterval和setTimeout,可以實現非常復雜的定時任務處理。然而,牛叉到無所不能的Python,卻沒有一個像樣的定時器,實在令人難以理解。

      剛入門的同學一定會說:不是有個time.sleep嗎?定好鬧鐘睡大覺,鬧鐘一響,起來干活,這不就是一個定時器嗎?沒錯,time.sleep具備定時器的基本要素,但若作為定時器使用,則有兩個致命的缺陷:一是阻塞主線程,睡覺的時候不能做任何事情;二是醒來以后需要主線程執行定時任務——即便使用線程技術,也得先由主線程來創建子線程。

      說到這里,熟悉線程模塊threading的同學也許會說:threading.Timer就是以線程方式運行的呀,既不會阻塞主線程,執行定時任務也無需主線程干預,這不就是一個完美的定時器嗎?

      我們先來看看threading.Timer是如何工作的。下面這段代碼演示了threading.Timer的基本用法:啟動定時器2秒鐘后以線程方式調用函數do_something,在定時器等待的2秒鐘內,以及do_something運行期間,主線程仍然可以做其他工作——此處是從鍵盤讀取輸入,借以阻塞主線程,以便觀察定時器的工作情況。

      import time import threading def do_something(name, gender='male'): print(time.time(), '定時時間到,執行特定任務' ) print('name:%s, gender:%s'%(name, gender)) timer = threading.Timer(2, do_something, args=('Alice',), kwargs={'gender':'female'}) timer.start() print(time.time(), '定時開始時間') input('按回車鍵結束\n') # 此處阻塞住進程

      正如我們所期待的那樣,定時器啟動2秒鐘后,函數do_something被調用,這期間可以隨時敲擊回車鍵結束程序。這段代碼的運行結果如下。

      1627438957.4297626 定時開始時間 按回車鍵結束 1627438959.4299397 定時時間到,執行特定任務 name:Alice, gender:female

      從使用效果看,threading.Timer稱得上是一款簡潔易用的定時器。不過,threading.Timer存在明顯的短板,那就是不支持連續的定時任務,比如,每隔2秒鐘調用一次do_something函數。如果一定要用threading.Timer實現連續定時,只能用類似嵌套的變通方法,在do_something函數中再次啟動定時器。

      無所不能的Python竟然沒有一個像樣的定時器?試試這個!

      import time import threading def do_something(name, gender='male'): global timer timer = threading.Timer(2, do_something, args=(name,), kwargs={'gender':gender}) timer.start() print(time.time(), '定時時間到,執行特定任務' ) print('name:%s, gender:%s'%(name, gender)) time.sleep(5) print(time.time(), '完成特定任務' ) timer = threading.Timer(2, do_something, args=('Alice',), kwargs={'gender':'female'}) timer.start() input('按回車鍵結束\n') # 此處阻塞住進程

      這段代碼重新定義了do_something函數,在函數開始位置啟動下一次的定時任務。之所以放在開始位置,是為了保證兩次定時之間的時間間隔盡可能精確。饒是如此,下面的運行結果顯示,兩次定時之間的時間間隔比設計的2秒鐘多了大約10毫秒,且誤差是連續累計的,重復執行100次,誤差將會超過1秒鐘。

      按回車鍵結束 1627440628.683803 定時時間到,執行特定任務 name:Alice, gender:female 1627440630.6929214 定時時間到,執行特定任務 name:Alice, gender:female 1627440632.707388 定時時間到,執行特定任務 name:Alice, gender:female 1627440633.6890671 完成特定任務 1627440634.722474 定時時間到,執行特定任務 name:Alice, gender:female 1627440635.7092102 完成特定任務 1627440636.7277966 定時時間到,執行特定任務 name:Alice, gender:female

      針對連續的定時任務,threading.Timer的表現還算差強人意,只是這種嵌套的寫法完全顛覆了代碼美學。對于像我這樣有代碼潔癖的程序員來說,是無法容忍和不可接受的。在我看來,一個完美的定時器應該滿足以下5個條件,具備下圖所示的結構。

      不阻塞主線程

      同時支持單次定時和連續定時

      以線程或進程方式執行定時任務

      定時任務的線程或進程的創建、運行,不影響定時精度

      足夠精確的定時精度,且誤差不會累計

      既然Python沒有提供一個像樣的定時器,那就自己寫一個吧。下面這個定時器,滿足上面提到的5個條件,最短時間間隔可以低至10毫秒,且誤差不會累計。雖然還不夠完美,但無論結構還是精度,都還說得過去。

      import time import threading class PyTimer: """定時器類""" def __init__(self, func, *args, **kwargs): """構造函數""" self.func = func self.args = args self.kwargs = kwargs self.running = False def _run_func(self): """運行定時事件函數""" th = threading.Thread(target=self.func, args=self.args, kwargs=self.kwargs) th.setDaemon(True) th.start() def _start(self, interval, once): """啟動定時器的線程函數""" if interval < 0.010: interval = 0.010 if interval < 0.050: dt = interval/10 else: dt = 0.005 if once: deadline = time.time() + interval while time.time() < deadline: time.sleep(dt) # 定時時間到,調用定時事件函數 self._run_func() else: self.running = True deadline = time.time() + interval while self.running: while time.time() < deadline: time.sleep(dt) # 更新下一次定時時間 deadline += interval # 定時時間到,調用定時事件函數 if self.running: self._run_func() def start(self, interval, once=False): """啟動定時器 interval - 定時間隔,浮點型,以秒為單位,最高精度10毫秒 once - 是否僅啟動一次,默認是連續的 """ th = threading.Thread(target=self._start, args=(interval, once)) th.setDaemon(True) th.start() def stop(self): """停止定時器""" self.running = False

      定時器類PyTimer實例化時,需要傳入定時任務函數。如果定時任務函數有參數,也可以按照位置參數、關鍵字參數的順序一并提供。PyTimer定時器提供start和stop兩個方法,用于啟動和停止定時器。其中stop方法不需要參數,start則需要一個以秒為單位的定時間隔參數。start還有一個布爾型的默認參數once,可以設置是否單次定時。once參數的默認值為False,即默認連續定時;如果需要單次定時,只需要將once置為true即可。

      def do_something(name, gender='male'): print(time.time(), '定時時間到,執行特定任務' ) print('name:%s, gender:%s'%(name, gender)) time.sleep(5) print(time.time(), '完成特定任務' ) timer = PyTimer(do_something, 'Alice', gender='female') timer.start(0.5, once=False) input('按回車鍵結束\n') # 此處阻塞住進程 timer.stop()

      上面是使用PyTimer定時器以0.5秒鐘的間隔連續調用函數do_something的例子。這段代碼的運行結果如下。

      按回車鍵結束 1627450313.425347 定時時間到,執行特定任務 name:Alice, gender:female 1627450313.9226055 定時時間到,執行特定任務 name:Alice, gender:female 1627450314.421761 定時時間到,執行特定任務 name:Alice, gender:female 1627450314.9243422 定時時間到,執行特定任務 name:Alice, gender:female 1627450315.422722 定時時間到,執行特定任務 name:Alice, gender:female 1627450315.9200313 定時時間到,執行特定任務 name:Alice, gender:female 1627450316.4204514 定時時間到,執行特定任務 name:Alice, gender:female 1627450316.9215539 定時時間到,執行特定任務 name:Alice, gender:female 1627450317.4228196 定時時間到,執行特定任務 name:Alice, gender:female 1627450317.9245899 定時時間到,執行特定任務 name:Alice, gender:female 1627450318.42355 定時時間到,執行特定任務 name:Alice, gender:female 1627450318.4393418 完成特定任務 1627450318.9251466 定時時間到,執行特定任務 name:Alice, gender:female 1627450318.9395308 完成特定任務 1627450319.4242043 完成特定任務 1627450319.4242043 定時時間到,執行特定任務 name:Alice, gender:female 1627450319.9253905 定時時間到,執行特定任務 name:Alice, gender:female 1627450319.9411068 完成特定任務 1627450320.425871 完成特定任務 1627450320.425871 定時時間到,執行特定任務 name:Alice, gender:female

      雖然每個定時任務需要運行5秒鐘,但每隔0.5秒都會準時啟動一個新的線程運行定時任務。從記錄可以看出,盡管每次定時任務的啟動時間有幾個毫秒的誤差,但誤差不會累計,重復執行的時間間隔均值始終穩定在0.5秒。

      Python 任務調度

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:Excel表格誤刪怎么恢復(電腦excel表格誤刪怎么恢復)
      下一篇:Excel2010工作表中設置打印區域實現只打印需要的部分內容(在excel中在文件中設置打印區域時將出現)
      相關文章
      久久亚洲精品视频| 亚洲乱码中文字幕在线| 亚洲av成人片在线观看| 77777午夜亚洲| 亚洲乱码一二三四区国产| 亚洲邪恶天堂影院在线观看| 亚洲精品国精品久久99热一| 国产亚洲AV夜间福利香蕉149| 亚洲乱亚洲乱少妇无码| 亚洲午夜av影院| 国产亚洲精品拍拍拍拍拍| 国产国拍亚洲精品福利| 国产日韩成人亚洲丁香婷婷| 亚洲一区视频在线播放| 亚洲国产精品成人网址天堂| 免费在线观看亚洲| 亚洲成AⅤ人影院在线观看| www国产亚洲精品久久久| 国产精品久久久久久亚洲小说| 亚洲丰满熟女一区二区哦| 亚洲国产成人久久精品软件| 亚洲精品无AMM毛片| 亚洲Av无码国产一区二区| 亚洲爆乳AAA无码专区| 亚洲av永久中文无码精品| 亚洲成av人无码亚洲成av人| 亚洲 欧洲 自拍 另类 校园| 亚洲欧美乱色情图片| 亚洲A∨无码无在线观看| 亚洲av麻豆aⅴ无码电影| 久久久久无码精品亚洲日韩| 中文亚洲成a人片在线观看| 国产中文在线亚洲精品官网| 亚洲无线观看国产精品| 亚洲av永久无码精品古装片| 亚洲人成电影福利在线播放| 亚洲色成人网一二三区| 77777亚洲午夜久久多喷| 亚洲一区二区三区高清在线观看 | 亚洲欧洲日本天天堂在线观看| 亚洲四虎永久在线播放|