asyncio create_task永远运行

时间:2018-05-29 20:35:17

标签: python python-3.x python-asyncio

我有以下代码

import asyncio

loop = asyncio.get_event_loop()

async def while_loop():
    n = 0
    while True:
        print(f"{n}")
        await asyncio.sleep(2)
        n = n+1

async def some_func():
    await asyncio.sleep(5)
    print("Some Func")

future = loop.create_task(while_loop())
loop.run_until_complete(some_func())

我希望while_loop函数能够永久运行,但它似乎只是在调用run_until_complete时执行,并且一旦some_func执行完毕就停止打印while循环。我看到的输出是:

0
1
2
Some Func

我预计即使在some_func完成后,这些数字也会继续打印。

0
1
2
Some Func
3
4
5
6
.
.
.

打印更多号码的唯一方法是再次拨打some_func

2 个答案:

答案 0 :(得分:9)

  

我预计即使在some_func完成后,这些数字也会继续打印。

run_until_complete的参数控制事件循环的运行时间。一旦事件循环停止运行,所有协同程序将被有效暂停,而不仅仅是您一直在等待的协同程序。但你有不同的选择:

  • loop.run_until_complete(some_func()) - 您已经使用过的;运行事件循环,直到some_func协程完成。在此期间也会并行执行其他协同程序,但在事件循环结束后也会停止执行它们。

  • loop.run_forever() - 运行事件循环,直到某个协程或回调调用loop.stop()。如果它们都不这样做,那么即使所有协同程序都结束,事件循环也不会停止。在您的情况下,您可以拨打loop.create_task(while_loop()),然后拨打loop.create_task(some_func()),然后拨打loop.run_forever()

  • loop.run_until_complete(asyncio.gather(while_loop(), some_func()))运行事件循环,直到两者指定的协同程序完成。这个(等待所有任务)显然是你期望loop.run_until_complete()自动完成的,即使你只命名一个,除非它不能那样工作,它会立即停止指定的协程完成。 asyncio.gather可用于同时等待多个协同程序。如需更精细地控制等待,请参阅asyncio.wait

由于你的一个协程永远运行,最后两个选项将是等效的,并将产生预期的输出。

答案 1 :(得分:-1)

这就是我用来让 async with 上下文永远活着的方法:

def never():
    try:
        return never.never
    except AttributeError:
        never.never = asyncio.Future()
        return never.never


async def create_context_and_dependent_tasks():
    async with create_ctx() as ctx:
        for i in range(10):
            asyncio.create_task(use_ctx_indefinitely(bar))

        await never()   # **THIS** is the main idea I wanted to talk about.

它不适用于多个循环,但这种情况很少发生(并且可以通过对 never 函数稍加修改来解决):

def never():
    loop = asyncio.get_running_loop()
    try:
        return never.nevers[loop]
    except KeyError:
        never.nevers[loop] = asyncio.Future()
    return never.nevers[loop]


never.nevers = {}

问题是,如果你创造了一个本地的未来:

async def foo():
    never = asyncio.Future()
    await never

它会被垃圾收集,任务会被销毁……仅仅因为 Python 充满了惊喜。所以你必须全局创建未来(但不是一开始,因为循环还不存在)。