最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Python實現(xiàn)一個優(yōu)雅的異步定時器

 更新時間:2025年04月20日 11:40:19   作者:有人說風輕的像雨  
在 Python 中實現(xiàn)定時器功能是一個常見需求,尤其是在需要周期性執(zhí)行任務(wù)的場景下,本文給大家介紹了基于 asyncio 和 threading 模塊,可擴展的異步定時器實現(xiàn),需要的朋友可以參考下

需求背景

定時器的核心功能是能夠周期性地觸發(fā)回調(diào)函數(shù),同時需要支持啟動、停止以及狀態(tài)檢查等操作。在多線程或異步編程場景中,希望定時器能夠:

  1. 支持異步操作,避免阻塞主線程;
  2. 單例化事件循環(huán),節(jié)省資源;
  3. 優(yōu)雅地管理定時器的生命周期;
  4. 提供簡單的接口,易于使用。

為此,設(shè)計了一個 Timer 類,結(jié)合 asyncio 和 threading,實現(xiàn)了一個高效的定時器。

代碼

完整代碼

import asyncio
import threading
import time
import sys

class Timer:
    _loop = None
    _thread = None
    _lock = threading.Lock()
    _running_timers = 0

    @classmethod
    def _ensure_loop(cls):
        with cls._lock:
            if cls._loop is None or not cls._thread or not cls._thread.is_alive():
                cls._loop = asyncio.new_event_loop()
                cls._thread = threading.Thread(
                    target=cls._run_loop,
                    args=(cls._loop,),
                    daemon=True
                )
                cls._thread.start()

    @classmethod
    def _run_loop(cls, loop):
        asyncio.set_event_loop(loop)
        try:
            loop.run_forever()
        except Exception as e:
            print(f"事件循環(huán)異常: {e}")
        finally:
            loop.close()

    @classmethod
    def _shutdown(cls):
        with cls._lock:
            if cls._running_timers == 0 and cls._loop is not None and cls._loop.is_running():
                cls._loop.call_soon_threadsafe(cls._loop.stop)
                # 不使用 join,因為守護線程會在主線程退出時自動結(jié)束

    def __init__(self):
        self.is_running = False
        self._stop_event = asyncio.Event()
        self._task = None

    async def _timer_loop(self, interval, callback):
        try:
            while not self._stop_event.is_set():
                await asyncio.sleep(interval)
                if not self._stop_event.is_set():
                    await asyncio.get_event_loop().run_in_executor(None, callback)
        except asyncio.CancelledError:
            pass  # 正常取消時忽略
        except Exception as e:
            print(f"定時器循環(huán)異常: {e}")
        finally:
            self.is_running = False
            Timer._running_timers -= 1
            Timer._shutdown()

    def start(self, interval, callback):
        if not self.is_running:
            Timer._ensure_loop()
            self.is_running = True
            self._stop_event.clear()
            self._task = asyncio.run_coroutine_threadsafe(
                self._timer_loop(interval, callback),
                Timer._loop
            )
            Timer._running_timers += 1
            # print(f"定時器已啟動,每{interval}秒執(zhí)行一次")

    def stop(self):
        if self.is_running:
            self._stop_event.set()
            if self._task:
                Timer._loop.call_soon_threadsafe(self._task.cancel)
            self.is_running = False
            # print("定時器已停止")

    def is_active(self):
        return self.is_running

# 使用示例
def callback1():
    print(f"回調(diào)1觸發(fā): {time.strftime('%H:%M:%S')}")

def callback2():
    print(f"回調(diào)2觸發(fā): {time.strftime('%H:%M:%S')}")

if __name__ == "__main__":
    timer1 = Timer()
    timer2 = Timer()

    timer1.start(2, callback1)
    timer2.start(3, callback2)

    try:
        time.sleep(100)
        timer1.stop()
        time.sleep(2)
        timer2.stop()
    except KeyboardInterrupt:
        timer1.stop()
        timer2.stop()
    finally:
        # 確保在程序退出時清理
        Timer._shutdown()

1. 單例事件循環(huán)的實現(xiàn)

為了避免每個定時器都創(chuàng)建一個獨立的事件循環(huán),在 Timer 類中使用了類變量和類方法來管理全局唯一的事件循環(huán):

class Timer:
    _loop = None
    _thread = None
    _lock = threading.Lock()
    _running_timers = 0

    @classmethod
    def _ensure_loop(cls):
        with cls._lock:
            if cls._loop is None or not cls._thread or not cls._thread.is_alive():
                cls._loop = asyncio.new_event_loop()
                cls._thread = threading.Thread(
                    target=cls._run_loop,
                    args=(cls._loop,),
                    daemon=True
                )
                cls._thread.start()
  • _loop:存儲全局的 asyncio 事件循環(huán)。
  • _thread:將事件循環(huán)運行在一個獨立的守護線程中,避免阻塞主線程。
  • _lock:線程鎖,確保在多線程環(huán)境中創(chuàng)建事件循環(huán)時的線程安全。
  • _ensure_loop:在需要時創(chuàng)建或重用事件循環(huán),確保只有一個全局循環(huán)。

守護線程(daemon=True)的設(shè)計使得程序退出時無需顯式關(guān)閉線程,簡化了資源清理。

2. 事件循環(huán)的運行與關(guān)閉

事件循環(huán)的運行邏輯封裝在 _run_loop 中:

@classmethod
def _run_loop(cls, loop):
    asyncio.set_event_loop(loop)
    try:
        loop.run_forever()
    except Exception as e:
        print(f"事件循環(huán)異常: {e}")
    finally:
        loop.close()
  • run_forever:讓事件循環(huán)持續(xù)運行,直到被外部停止。
  • 異常處理:捕獲可能的錯誤并打印,便于調(diào)試。
  • finally:確保循環(huán)關(guān)閉時資源被正確釋放。

關(guān)閉邏輯則由 _shutdown 方法控制:

@classmethod
def _shutdown(cls):
    with cls._lock:
        if cls._running_timers == 0 and cls._loop is not None and cls._loop.is_running():
            cls._loop.call_soon_threadsafe(cls._loop.stop)

當所有定時器都停止時(_running_timers == 0),事件循環(huán)會被安全停止。

3. 定時器核心邏輯

每個 Timer 實例負責管理一個獨立的定時任務(wù):

def __init__(self):
    self.is_running = False
    self._stop_event = asyncio.Event()
    self._task = None

async def _timer_loop(self, interval, callback):
    try:
        while not self._stop_event.is_set():
            await asyncio.sleep(interval)
            if not self._stop_event.is_set():
                await asyncio.get_event_loop().run_in_executor(None, callback)
    except asyncio.CancelledError:
        pass  # 正常取消時忽略
    finally:
        self.is_running = False
        Timer._running_timers -= 1
        Timer._shutdown()
  • _stop_event:一個 asyncio.Event 對象,用于控制定時器的停止。
  • _timer_loop:異步協(xié)程,每隔 interval 秒執(zhí)行一次回調(diào)函數(shù) callback
  • run_in_executor:將回調(diào)函數(shù)運行在默認的線程池中,避免阻塞事件循環(huán)。

4. 啟動與停止

啟動和停止方法是用戶的主要接口:

def start(self, interval, callback):
    if not self.is_running:
        Timer._ensure_loop()
        self.is_running = True
        self._stop_event.clear()
        self._task = asyncio.run_coroutine_threadsafe(
            self._timer_loop(interval, callback),
            Timer._loop
        )
        Timer._running_timers += 1

def stop(self):
    if self.is_running:
        self._stop_event.set()
        if self._task:
            Timer._loop.call_soon_threadsafe(self._task.cancel)
        self.is_running = False
  • start:啟動定時器,確保事件循環(huán)可用,并記錄運行中的定時器數(shù)量。
  • stop:通過設(shè)置 _stop_event 并取消任務(wù)來停止定時器。

5. 使用示例

以下是一個簡單的使用示例:

def callback1():
    print(f"回調(diào)1觸發(fā): {time.strftime('%H:%M:%S')}")

def callback2():
    print(f"回調(diào)2觸發(fā): {time.strftime('%H:%M:%S')}")

timer1 = Timer()
timer2 = Timer()

timer1.start(2, callback1)  # 每2秒觸發(fā)一次
timer2.start(3, callback2)  # 每3秒觸發(fā)一次

time.sleep(10)  # 運行10秒
timer1.stop()
timer2.stop()

輸出可能如下:

回調(diào)1觸發(fā): 14:30:02
回調(diào)2觸發(fā): 14:30:03
回調(diào)1觸發(fā): 14:30:04
回調(diào)1觸發(fā): 14:30:06
回調(diào)2觸發(fā): 14:30:06
...

設(shè)計亮點

  1. 異步與多線程結(jié)合:通過 asyncio 和 threading,實現(xiàn)了非阻塞的定時器,適合高并發(fā)場景。
  2. 資源高效利用:全局唯一的事件循環(huán)避免了重復(fù)創(chuàng)建的開銷。
  3. 優(yōu)雅的生命周期管理:守護線程和自動關(guān)閉機制簡化了資源清理。
  4. 線程安全:使用鎖機制確保多線程環(huán)境下的穩(wěn)定性。

適用場景

  • 周期性任務(wù)調(diào)度,如數(shù)據(jù)刷新、狀態(tài)檢查。
  • 后臺服務(wù)中的定時監(jiān)控。
  • 游戲或?qū)崟r應(yīng)用中的計時器需求。

總結(jié)

這個異步定時器實現(xiàn)結(jié)合了 Python 的異步編程和多線程特性,提供了一個輕量、靈活的解決方案。無論是簡單的腳本還是復(fù)雜的后臺服務(wù),它都能勝任。如果你需要一個可靠的定時器,不妨試試這個實現(xiàn),或者根據(jù)需求進一步優(yōu)化它!

以上就是使用Python實現(xiàn)一個優(yōu)雅的異步定時器的詳細內(nèi)容,更多關(guān)于Python異步定時器的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python面向?qū)ο蟪绦蛟O(shè)計之繼承與多繼承用法分析

    Python面向?qū)ο蟪绦蛟O(shè)計之繼承與多繼承用法分析

    這篇文章主要介紹了Python面向?qū)ο蟪绦蛟O(shè)計之繼承與多繼承用法,結(jié)合實例形式分析了Python繼承與多繼承的簡單定義與使用方法,需要的朋友可以參考下
    2018-07-07
  • OPCUA-Python實例

    OPCUA-Python實例

    這篇文章主要介紹了OPCUA-Python實例,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • django 刪除數(shù)據(jù)庫表后重新同步的方法

    django 刪除數(shù)據(jù)庫表后重新同步的方法

    今天小編就為大家分享一篇django 刪除數(shù)據(jù)庫表后重新同步的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • python實現(xiàn)txt文件格式轉(zhuǎn)換為arff格式

    python實現(xiàn)txt文件格式轉(zhuǎn)換為arff格式

    這篇文章主要為大家詳細介紹了python實現(xiàn)txt文件格式轉(zhuǎn)換為arff格式的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • Python中的字符串查找操作方法總結(jié)

    Python中的字符串查找操作方法總結(jié)

    這里我們來整理一下Python中的字符串查找操作方法總結(jié),除了基本的find()方法外,還會講解到樸素匹配算法和KMP算法的使用:
    2016-06-06
  • Python中最大最小賦值小技巧(分享)

    Python中最大最小賦值小技巧(分享)

    下面小編就為大家分享一篇Python中最大最小賦值小技巧,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • Python數(shù)據(jù)處理篇之Sympy系列(五)---解方程

    Python數(shù)據(jù)處理篇之Sympy系列(五)---解方程

    這篇文章主要介紹了Python數(shù)據(jù)處理篇之Sympy系列(五)---解方程,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-10-10
  • Python實現(xiàn)滑塊拼圖驗證碼詳解

    Python實現(xiàn)滑塊拼圖驗證碼詳解

    驗證碼作為一種自然人的機器人的判別工具,被廣泛的用于各種防止程序做自動化的場景中。傳統(tǒng)的字符型驗證安全性已經(jīng)名存實亡的情況下,各種新型的驗證碼如雨后春筍般涌現(xiàn),今天給大家分享一篇Python實現(xiàn)滑塊驗證碼
    2022-05-05
  • python使用Flask操作mysql實現(xiàn)登錄功能

    python使用Flask操作mysql實現(xiàn)登錄功能

    這篇文章主要介紹了python使用Flask操作mysql實現(xiàn)登錄功能,代碼簡單易懂,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-05-05
  • 五個Python迷你版小程序附代碼

    五個Python迷你版小程序附代碼

    在使用Python的過程中,我最喜歡的就是Python的各種第三方庫,能夠完成很多操作。下面就給大家介紹5個通過 Python 構(gòu)建的實戰(zhàn)項目,來實踐 Python 編程能力。歡迎收藏學習,喜歡點贊支持
    2021-11-11

最新評論

绥滨县| 扶风县| 曲麻莱县| 阳信县| 辽宁省| 孝昌县| 邵武市| 永吉县| 闽侯县| 大渡口区| 白山市| 崇明县| 封开县| 上虞市| 汝阳县| 准格尔旗| 汝阳县| 嘉禾县| 紫阳县| 永仁县| 宣化县| 霍山县| 东至县| 万宁市| 包头市| 昌江| 郎溪县| 阿巴嘎旗| 呼和浩特市| 甘南县| 赤峰市| 平乡县| 金华市| 广宗县| 中牟县| 永昌县| 莱州市| 玉门市| 改则县| 西宁市| 宜宾市|