如何运行协程而不等待它?

时间:2019-08-23 10:48:07

标签: python python-asyncio

我有一个非异步函数,如下所示:

def do_stuff(on_finished):
    result = # complicated calculations here
    on_finished(result)

我传入的回调或多或少是这样的:

async def on_finished(self, result):
    response = await post_over_http(result)
    self.last_status = response.status 

当我打电话给do_stuff时,我想发生的事情是这样的:

  1. do_stuff执行并调用on_finished
  2. on_finished执行,通过HTTP发布结果,然后立即返回。
  3. do_stuff现在立即返回。
  4. 稍后,HTTP响应返回,执行返回到on_finished的第二行。

至关重要的是,我不希望do_stuff异步。出于架构上的原因,我希望do_stuff与网络代码的异步性质隔离,所以我不想仅由于使用它的某些代码是异步的而使其异步。

在JavaScript中这没问题-基本上将上面的代码直接转录为JavaScript,我将获得所需的行为。 onFinished将返回一个承诺,doStuff不会等待并立即返回,但是当该承诺稍后解析时,onFinished的第二行就会运行。这在Python中可行吗?我不确定如何实现。使用以上代码,我想我只是在do_stuff的最后一行中创建了一个协程,但从未调用它。

4 个答案:

答案 0 :(得分:1)

您可以这样设计do_stuff函数:

def do_stuff(on_finished):
    async def _do_complicated_calculation():
        result = # do the calculation here & the post request
        await on_finished(result)
    asyncio.ensure_future(_do_complicated_calculation())
    return "ok"

当您调用do_stuff(...)时,复杂的计算将添加到asyncio事件循环中,因此它将异步执行。如果您不打算在主线程中启动事件循环,则应在另一个线程中运行该事件循环。

由于_do_complicated_calculation()是异步的,因此do_stuff将首先返回"ok",并且在计算完成之后,将调用on_finished(...)

答案 1 :(得分:0)

这就是为什么Javascript与Python行为不同的原因。

  

ECMAScript 2015引入了作业队列的概念,   由Promises(也在ES6 / ES2015中引入)。这是执行   异步功能的结果,而不是被放置   在调用堆栈的末尾。

     

在当前功能结束之前解决的承诺将是   在当前函数之后立即执行。

https://nodejs.dev/the-nodejs-event-loop

答案 2 :(得分:0)

同步函数不传递回调,而是返回其结果,并使用run_in_executor进行从异步代码到将在其自己的线程上运行的同步代码的调用。

def do_stuff():
    result = # complicated calculations here
    return result

async def main():
    loop = asyncio.get_event_loop()
    result = await loop.run_in_executor(None, do_stuff)
    response = await post_over_http(result)
    self.last_status = response.status 

未经测试。

答案 3 :(得分:-1)

如果我了解JavaScript的类比,那么您想要的是这样的:

def do_stuff(on_finished):
    result = ...
    asyncio.create_task(on_finished(result))

最后一行产生一个处理结果的任务,而无需实际等待它完成。这是您在JavaScript中通过简单地创建一个Promise就能得到的,而在Python中,您必须更加明确。

当然,do_stuff必须在事件循环内运行,并且计算不得阻塞(或花费太长时间才能完成),但JavaScript就是这种情况。