Issue
I'm trying my hand at asyncio in Python 3.6 and having a hard time figuring out why this piece of code is behaving the way it is.
Example code:
import asyncio
async def compute_sum(x, y):
print("Compute %s + %s ..." % (x, y))
await asyncio.sleep(5)
print("Returning sum")
return x + y
async def compute_product(x, y):
print("Compute %s x %s ..." % (x, y))
print("Returning product")
return x * y
async def print_computation(x, y):
result_sum = await compute_sum(x, y)
result_product = await compute_product(x, y)
print("%s + %s = %s" % (x, y, result_sum))
print("%s * %s = %s" % (x, y, result_product))
loop = asyncio.get_event_loop()
loop.run_until_complete(print_computation(1, 2))
Output:
Compute 1 + 2 ...
Returning sum
Compute 1 x 2 ...
Returning product
1 + 2 = 3
1 * 2 = 2
Expected Output:
Compute 1 + 2 ...
Compute 1 x 2 ...
Returning product
Returning sum
1 + 2 = 3
1 * 2 = 2
My reasoning for expected output:
While the compute_sum coroutine is correctly called before the compute_product coroutine, my understanding was that once we hit await asyncio.sleep(5)
, the control would be passed back to the event loop which would start the execution of the compute_product coroutine. Why is "Returning sum" being executed before we hit the print statement in the compute_product coroutine?
Solution
You're right about how the coroutines work; your problem is in how you're calling them. In particular:
result_sum = await compute_sum(x, y)
This calls the coroutine compute_sum
and then waits until it finishes.
So, compute_sum
does indeed yield to the scheduler in that await asyncio.sleep(5)
, but there's nobody else to wake up. Your print_computation
coro is already awaiting compute_sum
. And nobody's even started compute_product
yet, so it certainly can't run.
If you want to spin up multiple coroutines and have them run concurrently, don't await
each one; you need to await the whole lot of them together. For example:
async def print_computation(x, y):
awaitable_sum = compute_sum(x, y)
awaitable_product = compute_product(x, y)
result_sum, result_product = await asyncio.gather(awaitable_sum, awaitable_product)
print("%s + %s = %s" % (x, y, result_sum))
print("%s * %s = %s" % (x, y, result_product))
(It doesn't matter whether awaitable_sum
is a bare coroutine, a Future
object, or something else that can be await
ed; gather
works either way.)
Or, maybe more simply:
async def print_computation(x, y):
result_sum, result_product = await asyncio.gather(
compute_sum(x, y), compute_product(x, y))
print("%s + %s = %s" % (x, y, result_sum))
print("%s * %s = %s" % (x, y, result_product))
See Parallel execution of tasks in the examples section.
Answered By - abarnert
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.