【问题标题】:How to schedule a task in asyncio so it runs at a certain date?如何在 asyncio 中安排任务以使其在特定日期运行?
【发布时间】:2018-12-19 21:09:06
【问题描述】:

我的程序应该 24/7 运行,我希望能够在某个时间/日期运行一些任务。

我已经尝试过使用aiocron,但它只支持调度函数(不支持协程),我读过这不是一个非常好的库。 我的程序是这样构建的,即使不是所有我想要安排的任务都内置在协程中。

是否有任何其他库允许进行此类任务调度?

如果不是,是否有任何方式扭曲协程以使其运行正常功能?

【问题讨论】:

    标签: python scheduled-tasks python-asyncio


    【解决方案1】:

    我已经尝试过使用 aiocron,但它只支持调度功能(不支持协程)

    根据您提供的link 中的示例,情况似乎并非如此。 @asyncio.coroutine修饰的函数相当于async def定义的协程,可以互换使用。

    但是,如果您想避免使用 aiocron,可以直接使用 asyncio.sleep 将协程的运行推迟到任意时间点。例如:

    import asyncio, datetime
    
    async def wait_until(dt):
        # sleep until the specified datetime
        now = datetime.datetime.now()
        await asyncio.sleep((dt - now).total_seconds())
    
    async def run_at(dt, coro):
        await wait_until(dt)
        return await coro
    

    示例用法:

    async def hello():
        print('hello')
    
    loop = asyncio.get_event_loop()
    # print hello ten years after this answer was written
    loop.create_task(run_at(datetime.datetime(2028, 7, 11, 23, 36),
                            hello()))
    loop.run_forever()
    

    注意:3.8 之前的 Python 版本不支持超过 24 天的睡眠间隔,因此 wait_until 必须解决这个限制。这个答案的原始版本是这样定义的:

    async def wait_until(dt):
        # sleep until the specified datetime
        while True:
            now = datetime.datetime.now()
            remaining = (dt - now).total_seconds()
            if remaining < 86400:
                break
            # pre-3.7.1 asyncio doesn't like long sleeps, so don't sleep
            # for more than one day at a time
            await asyncio.sleep(86400)
        await asyncio.sleep(remaining)
    

    在 Python 3.8 中的限制是 removed,并且该修复已向后移植到 3.6.7 和 3.7.1。

    【讨论】:

    • 为什么不使用loop.call_at
    • @Vincent loop.call_at 接受相对于loop.time() 返回的时间的时间参考,因此您仍然需要计算并且不能只给它一个例如Unix 时间戳。第二个问题是call_at 接受一个函数,而不是协程,所以你仍然需要一个调用create_task 的蹦床。使用call_at(和call_latercall_soon)你不能轻易地获得协程的返回值,就像在编辑的答案中所做的那样。
    • @Vincent 我在测试代码时发现了超时错误,方法是从现在开始安排一个事件。查看the source,限制似乎是最接近的超时(以毫秒为单位)不得超过 2**31-1,这意味着如果没有答案中的循环之类的解决方法,您的睡眠时间不能超过 24.8 天。对于 asyncio 的大多数实际用途,这不是问题,但是对于在特定 日期 运行任务的调度程序来说,它必须得到解决。
    • 有趣,我在 python 错误跟踪器上找到了这个related issue (bpo-20423)。解决此问题的另一种方法是schedule a background task that wakes up every day
    • 所以少睡从来都不是问题,这些超时根本不会触发,将留待下一次等待。换句话说,循环就在事件循环中。 (戴上 Horatio 眼镜)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-18
    • 2020-09-21
    • 2022-07-11
    • 1970-01-01
    • 2016-06-12
    • 2012-09-18
    相关资源
    最近更新 更多