Asyncio获取长时间运行的代码的状态

时间:2019-01-30 19:42:11

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

我有一些将在服务器中运行的代码。运行可能需要很长时间(至少几分钟)。我希望能够轮询服务器以了解当前代码在哪里。我以为可以使用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更改为“ running”,然后等待30秒,然后再将状态更改为“ finish”。同时,我应该回到控制台提示符,并且可以通过键入get_status()来获取当前状态。

实际上发生的是变量the_status从未从其初始状态'idle'改变。

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

我的Python版本是3.6。

1 个答案:

答案 0 :(得分:1)

  

我做错什么了吗?

代码有两个问题:

  • main仅创建任务而无需等待-您可以将create_task视为创建“后台”任务。但是在异步环境中,任务仅在主循环中运行,因此run_until_complete(main())立即退出,因为main()在创建任务后立即返回。随着主循环的停止,waiting任务没有机会开始执行。

  • waiting调用time.sleep,这在asyncio中是不允许的。 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'