首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何定期使用异步执行函数?

如何定期使用异步执行函数?
EN

Stack Overflow用户
提问于 2016-05-29 16:17:38
回答 9查看 99K关注 0票数 94

我正在从tornado迁移到asyncio,我找不到tornadoPeriodicCallbackasyncio等价物( PeriodicCallback有两个参数:要运行的函数和调用之间的毫秒数)。

  • asyncio中有这样的等价物吗?
  • 如果不是,在不冒过一段时间后获得RecursionError的风险的情况下,实现这一点的最干净的方法是什么?
EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2016-05-29 16:53:44

对于3.5以下的Python版本:

代码语言:javascript
运行
复制
import asyncio

@asyncio.coroutine
def periodic():
    while True:
        print('periodic')
        yield from asyncio.sleep(1)

def stop():
    task.cancel()

loop = asyncio.get_event_loop()
loop.call_later(5, stop)
task = loop.create_task(periodic())

try:
    loop.run_until_complete(task)
except asyncio.CancelledError:
    pass

对于Python3.5及以上版本:

代码语言:javascript
运行
复制
import asyncio

async def periodic():
    while True:
        print('periodic')
        await asyncio.sleep(1)

def stop():
    task.cancel()

loop = asyncio.get_event_loop()
loop.call_later(5, stop)
task = loop.create_task(periodic())

try:
    loop.run_until_complete(task)
except asyncio.CancelledError:
    pass
票数 86
EN

Stack Overflow用户

发布于 2016-05-29 20:27:12

当您觉得应该在异步程序的“背景”中发生一些事情时,asyncio.Task可能是很好的方法。您可以阅读这个职位来了解如何处理任务。

下面是定期执行某些函数的类的可能实现:

代码语言:javascript
运行
复制
import asyncio
from contextlib import suppress


class Periodic:
    def __init__(self, func, time):
        self.func = func
        self.time = time
        self.is_started = False
        self._task = None

    async def start(self):
        if not self.is_started:
            self.is_started = True
            # Start task to call func periodically:
            self._task = asyncio.ensure_future(self._run())

    async def stop(self):
        if self.is_started:
            self.is_started = False
            # Stop task and await it stopped:
            self._task.cancel()
            with suppress(asyncio.CancelledError):
                await self._task

    async def _run(self):
        while True:
            await asyncio.sleep(self.time)
            self.func()

让我们来测试一下:

代码语言:javascript
运行
复制
async def main():
    p = Periodic(lambda: print('test'), 1)
    try:
        print('Start')
        await p.start()
        await asyncio.sleep(3.1)

        print('Stop')
        await p.stop()
        await asyncio.sleep(3.1)

        print('Start')
        await p.start()
        await asyncio.sleep(3.1)
    finally:
        await p.stop()  # we should stop task finally


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

输出:

代码语言:javascript
运行
复制
Start
test
test
test

Stop

Start
test
test
test

[Finished in 9.5s]

正如您在start上看到的,我们只是启动任务,调用一些函数,并在没完没了的循环中休眠一段时间。在stop上,我们只是取消了这个任务。注意,该任务应该在程序完成时停止。

更重要的是,您的回调不需要花费太多时间来执行(否则会冻结事件循环)。如果您计划调用一些长期运行的func,您可能需要在执行器中运行它

票数 36
EN

Stack Overflow用户

发布于 2016-05-29 16:41:05

没有内置的支持定期呼吁,没有。

只需创建您自己的调度器循环,该循环可以休眠并执行任何已调度的任务:

代码语言:javascript
运行
复制
import math, time

async def scheduler():
    while True:
        # sleep until the next whole second
        now = time.time()
        await asyncio.sleep(math.ceil(now) - now)
       
        # execute any scheduled tasks
        async for task in scheduled_tasks(time.time()):
            await task()

scheduled_tasks()迭代器应该生成可以在给定时间运行的任务。请注意,理论上,生成计划和启动所有任务可能需要超过1秒的时间;这里的想法是,调度程序生成自上次检查以来应该启动的所有任务。

票数 28
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37512182

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档