从作为异步任务运行的函数中获取值

Posted

技术标签:

【中文标题】从作为异步任务运行的函数中获取值【英文标题】:Getting values from functions that run as asyncio tasks 【发布时间】:2015-09-08 11:41:29 【问题描述】:

我正在尝试以下代码:

import asyncio

@asyncio.coroutine
def func_normal():
        print("A")
        yield from asyncio.sleep(5)
        print("B")
        return 'saad'

@asyncio.coroutine
def func_infinite():
    i = 0
    while i<10:
        print("--"+str(i))
        i = i+1
    return('saad2')

loop = asyncio.get_event_loop()

tasks = [
    asyncio.async(func_normal()),
    asyncio.async(func_infinite())]

loop.run_until_complete(asyncio.wait(tasks))
loop.close()

我不知道如何从这些函数中获取变量中的值。我不能这样做:

asyncio.async(a = func_infinite())

因为这会使 this 成为关键字参数。我该怎么做呢?

【问题讨论】:

【参考方案1】:

协程按原样工作。只需使用loop.run_until_complete() 和call asyncio.gather() to collect multiple results 的返回值即可:

#!/usr/bin/env python3
import asyncio

@asyncio.coroutine
def func_normal():
    print('A')
    yield from asyncio.sleep(5)
    print('B')
    return 'saad'

@asyncio.coroutine
def func_infinite():
    for i in range(10):
        print("--%d" % i)
    return 'saad2'

loop = asyncio.get_event_loop()
tasks = func_normal(), func_infinite()
a, b = loop.run_until_complete(asyncio.gather(*tasks))
print("func_normal()=a, func_infinite()=b".format(**vars()))
loop.close()

输出

--0
--1
--2
--3
--4
--5
--6
--7
--8
--9
A
B
func_normal()=saad, func_infinite()=saad2

【讨论】:

这行得通。我确实使用这种方法同时为我的 django 应用程序运行了函数,但我没有看到性能上的提升。处理时间相同。 @AleemSaadullah: asyncio 允许您在 5 秒而不是 50 秒内运行 10 个func_normal() 任务。所有任务都在同一个线程中执行,除非您使用执行器将一些工作卸载到线程/进程池。我不熟悉使用 asyncio 运行 django(如果它甚至可能,或者如果没有在 django 中进行实质性重组是否有意义)。 是的,该代码适用于此处定义的函数。但我想,mongodb ORM(mongoengine) 应该支持异步查询。我认为这就是问题所在。 我实际项目中的函数主要是构建查询并执行它们。【参考方案2】:

loop.run_until_complete 返回您传递给它的函数返回的值。所以,它会返回asyncio.wait的输出:

import asyncio

@asyncio.coroutine
def func_normal():
    print("A")
    yield from asyncio.sleep(5)
    print("B")
    return 'saad'

@asyncio.coroutine
def func_infinite():
    i = 0
    while i<10:
        print("--"+str(i))
        i = i+1
    return('saad2')

loop = asyncio.get_event_loop()

tasks = [
    asyncio.async(func_normal()),
    asyncio.async(func_infinite())]

done, _ = loop.run_until_complete(asyncio.wait(tasks))
for fut in done:
    print("return value is ".format(fut.result()))
loop.close()

输出:

A
--0
--1
--2
--3
--4
--5
--6
--7
--8
--9
B
return value is saad2
return value is saad

您也可以直接从tasks 数组访问结果:

print(tasks[0].result())
print(tasks[1].result())

【讨论】:

【参考方案3】:

如果您想在协程结束后立即使用协程返回的任何值,您可以将未来对象传递给 coro 并通过计算值更新这个未来。一旦future被更新,它就会将future.result()传递给与给定future绑定的回调函数。见以下代码:

import asyncio


async def func_normal(future):
    print("A")
    await asyncio.sleep(5)
    print("B")
    # return 'saad'
    future.set_result('saad')


async def func_infinite(future):
    i = 0
    while i<10:
        print("--"+str(i))
        i = i+1
    # return('saad2')
    future.set_result('saad2')

def got_result(future):
    print(future.result())

loop = asyncio.get_event_loop()
future1 = asyncio.Future()
future2 = asyncio.Future()

future1.add_done_callback(got_result)
future2.add_done_callback(got_result)

# Coros are automatically wrapped in Tasks by asyncio.wait() 
coros = [
    func_normal(future1),
    func_infinite(future2)]

loop.run_until_complete(asyncio.wait(coros))
loop.close()

回调函数使用单个参数调用 - 它绑定的未来对象。如果您需要将更多参数传递到回调中,请使用 functools 包中的 partial:

future1.add_done_callback(functools.partial(print, "future:", argin))

会打电话

print("future:", argin)

【讨论】:

以上是关于从作为异步任务运行的函数中获取值的主要内容,如果未能解决你的问题,请参考以下文章

从异步任务中获取 LatLngs

回调函数

IOS Swift我如何从异步方法中获得价值[重复]

Java8——异步编程

使用celery的backend异步获取结果

将异步协程作为 celery 任务运行