异步以获取长时间运行的代码的状态



我有一些代码将在服务器中运行。跑步可能需要很长时间(至少几分钟)。我希望能够在服务器上轮询它当前在代码中的位置。我想我可以使用asyncio来完成这项工作,但看起来它可能不是我需要的。

以下是我为测试它而编写的一些代码(保存为test_async.py):

import asyncio
import time
the_status = 'idle'

async def waiting():
global the_status
await asyncio.sleep(0.001)
the_status = 'running'
time.sleep(30)
the_status = 'finished'

def get_status():
global the_status
return the_status

async def main():
loop.create_task(waiting())

loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.close()

我通过打开Python控制台并键入:来运行此操作

from test_async import *

我所期望的是,它将开始运行waiting(),将the_status更改为"正在运行",然后等待30秒,然后将状态更改为"已完成"。同时,我应该会得到控制台提示,我可以通过键入get_status()来获得当前状态。

实际发生的情况是,变量the_status从未从其"空闲"的初始状态改变。

我做错什么了吗?异步不是我想要做的事情的答案吗?

我的Python版本是3.6。

我做错了什么吗?

代码有两个问题:

  • main只是创建一个任务而不等待它——您可以将create_task视为创建一个"后台"任务。但在异步后台任务中,只有主循环才能运行,所以run_until_complete(main())会立即退出,因为main()会在创建任务后立即返回。随着主循环的停止,waiting任务没有机会开始执行。

  • waiting调用time.sleep,这在异步中是不允许的。Asyncio是一个协作的多任务系统,用于JS风格的回调和协同程序,当它们等待阻塞时会挂起自己。time.sleep并没有挂起,它只是阻塞了整个事件循环线程。使用run_in_executor可以正确地执行asyncio内部的遗留阻塞代码。

异步不是我想要做的事情的答案吗?

如果您有一些需要"在后台"执行的阻塞代码,则应该使用线程。

import time, concurrent.futures
the_status = 'idle'
def waiting():
global the_status
time.sleep(0.001)
the_status = 'running'
time.sleep(30)
the_status = 'finished'
executor = concurrent.futures.ThreadPoolExecutor()
executor.submit(waiting)

导入代码按预期工作:

>>> import thr2
>>> thr2.the_status
'running'

最新更新