簡體   English   中英

Python:如何通過順序執行實現異步調度程序?

[英]Python: How to implement async scheduler with sequential execution?

我想要一個用於“操作”執行的異步調度程序,它滿足 cerrain 屬性:

  1. 操作是一次性的,並按確切的時間戳進行安排。
  2. 動作應該嚴格按照順序執行,即調度器在前一個動作完成之前不能啟動下一個動作。
  3. 在動作的執行之間,當調度器等待下一個時間戳時,調度器必須處於asyncio.sleep()狀態才能讓其他協程asyncio.sleep()它們。
  4. 當調度新動作時,調度器應該立即重新調整它的等待時間,以便調度器始終等待最快的動作。
  5. 當沒有調度任何動作時,調度器應該處於asyncio.sleep()的永久狀態,直到添加新的動作。

我的嘗試:


import asyncio
import time

class Action:

    def __init__(self, timestamp):
        self.timestamp = timestamp

    async def do(self):
        print("Doing action...")

class Scheduler:

    def __init__(self):
        self._actions = []
        self._sleep_future = None

    def add(self, action):
        self._actions.append(action)
        self._actions.sort(key=lambda x: x.timestamp)

        if self._sleep_future:
            self._sleep_future.cancel()

    def pop(self):
        return self._actions.pop(0)

    async def start(self):
        asyncio.create_task(self.loop())

    async def loop(self):
        while True:
            now = time.time()            
            while self._actions:
                action = self._actions[0]
                if action.timestamp <= now:
                    action = self.pop()                
                    await action.do()                   
                else:
                    break

            self._sleep_future = asyncio.ensure_future(
                asyncio.sleep(self._actions[0].timestamp - now)
            )

            try:
                await self._sleep_future
            except asyncio.CancelledError:
                continue
            finally:
                self._sleep_future = None


這個實現是不可靠的,也沒有考慮到我尋求的條件(5)!

你能給我推薦一些東西嗎?

asyncio 事件循環已經包含您嘗試實現的代碼 - 排序超時並等待提交任務。 您需要使Scheduler的接口適應底層的 asyncio 功能,例如:

class Scheduler:
    def __init__(self):
        self._running = asyncio.Lock()

    async def start(self):
        pass  # asyncio event loop will do the actual work

    def add(self, action):
        loop = asyncio.get_event_loop()
        # Can't use `call_at()` because event loop time uses a
        # different timer than time.time().
        loop.call_later(
            action.timestamp - time.time(),
            loop.create_task, self._execute(action)
        )

    async def _execute(self, action):
        # Use a lock to ensure that no two actions run at
        # the same time.
        async with self._running:
            await action.do()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM