带有 call_later 的 Python 异步递归

Tim*_*hes 3 python recursion python-asyncio

我正在尝试创建一个简单的监控系统,它会定期检查事物并记录它们。这是我尝试使用的逻辑的简化示例,但我不断收到RuntimeWarning: coroutine 'foo' was never awaited错误消息。

我应该如何从自身重新安排异步方法?

test.py 中的代码:

import asyncio
from datetime import datetime

async def collect_data():
    await asyncio.sleep(1)
    return {"some_data": 1,}

async def foo(loop):
    results = await collect_data()
    # Log the results
    print("{}: {}".format(datetime.now(), results))
    # schedule to run again in X seconds
    loop.call_later(5, foo, loop)

if __name__ == '__main__':

    loop = asyncio.get_event_loop()
    loop.create_task(foo(loop))
    loop.run_forever()
    loop.close()
Run Code Online (Sandbox Code Playgroud)

错误:

pi@raspberrypi [0] $ python test.py 
2018-01-03 01:59:22.924871: {'some_data': 1}
/usr/lib/python3.5/asyncio/events.py:126: RuntimeWarning: coroutine 'foo' was never awaited
  self._callback(*self._args)
Run Code Online (Sandbox Code Playgroud)

Mik*_*mov 7

call_later 接受一个简单的同步回调(一个用 定义的函数def)。async def应等待执行协程函数 ( )。


很酷的一点asyncio是它在很多方面模仿了命令式纯同步代码。您将如何为普通函数解决此任务?我想只是睡一会儿,然后再次递归调用函数。也做同样的事情(几乎 - 我们应该使用同步睡眠)asyncio

import asyncio
from datetime import datetime


async def collect_data():
    await asyncio.sleep(1)
    return {"some_data": 1,}


async def foo(loop):
    results = await collect_data()

    # Log the results
    print("{}: {}".format(datetime.now(), results))

    # Schedule to run again in X seconds
    await asyncio.sleep(5)
    return (await foo(loop))


if __name__ ==  '__main__':
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(foo(loop))
    finally:
        loop.run_until_complete(loop.shutdown_asyncgens())  # Python 3.6 only
        loop.close()
Run Code Online (Sandbox Code Playgroud)

如果您有时需要foo与其他协程一起在后台运行,您可以创建一个任务。还显示了一种取消任务执行的方法。

更新:

正如安德鲁指出的那样,一个简单的循环甚至更好:

async def foo(loop):
    while True:
        results = await collect_data()

        # Log the results
        print("{}: {}".format(datetime.now(), results))

        # Wait before next iteration:
        await asyncio.sleep(5)
Run Code Online (Sandbox Code Playgroud)

  • 循环而不是递归调用更好。 (2认同)