我有以下代码
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
。
答案 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 充满了惊喜。所以你必须全局创建未来(但不是一开始,因为循环还不存在)。