Getting values from functions that run as asyncio tasks

PythonPython 3.xPython 3.4Python Asyncio

Python Problem Overview


I was trying the following code:

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()

I can't figure out how to get values in variables from these functions. I can't do this:

asyncio.async(a = func_infinite())

as this would make this a keyword argument. How do I go about accomplishing this?

Python Solutions


Solution 1 - Python

The coroutines work as is. Just use the returned value from loop.run_until_complete() and 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()
Output
--0
--1
--2
--3
--4
--5
--6
--7
--8
--9
A
B
func_normal()=saad, func_infinite()=saad2

Solution 2 - Python

loop.run_until_complete returns the value returned by the function you pass into it. So, it will return the output of 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()

Output:

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

You can also access the results directly from the tasks array:

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

Solution 3 - Python

If you want to use any value returned by coroutine as soon as coroutine ends you can pass future object into the coro and update this future by computed value. As soon as future is updated it passes its future.result() to the callback function which is bound with given future. See code below:

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()

The callback function is called with a single argument - the future object which it is bound with. If you need to pass more arguments into the callback use partial from functools package:

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

will call

print("future:", argin)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSaad AleemView Question on Stackoverflow
Solution 1 - PythonjfsView Answer on Stackoverflow
Solution 2 - PythondanoView Answer on Stackoverflow
Solution 3 - PythonPetr JavorikView Answer on Stackoverflow