I am new to asyncio and trying to understand basic for loop behavior. The code below executes sequentially, but my naive assumption was that while the sleeps are occurring, other items could be fetched via the for loop and start processing. But that doesn't seem to happen.
For example, while the code is "doing something else with 1" it seems like it could fetch the next item from the loop and start working on it while waiting for the sleep to end on item 1. But when I run, it executes sequentially with pauses for the sleeps like a non-async program.
What am I missing here?
import asyncio
class CustomIterator():
def __init__(self):
self.counter = 0
def __aiter__(self):
return self
async def __anext__(self):
if self.counter >= 3:
raise StopAsyncIteration
await asyncio.sleep(1)
self.counter += 1
return self.counter
async def f(item):
print(f"doing something with {item}")
await asyncio.sleep(3)
async def f2(item):
print(f"doing something else with {item}")
await asyncio.sleep(2)
async def do_async_stuff():
async for item in CustomIterator():
print(f"got {item}")
await f(item)
await f2(item)
if __name__ == '__main__':
asyncio.run(do_async_stuff())
Output:
got 1
doing something with 1
doing something else with 1
got 2
doing something with 2
doing something else with 2
got 3
doing something with 3
doing something else with 3
The entire point of await
is to create a sequence and yield point: when you await foo
, the goal is to give control to the executor so it can run other tasks, until whatever foo
is resolves and you get control back.
If you want to create concurrency in async code, you need to either:
create_task
), each task is an other thing the executor can run while one task is await-ingwait
, as_completed
, or gather
which register multiple objects against the executor at the same time, this way their asynchronous resolution will overlap rather than chainI think you have a common misunderstanding of how async
works. You have written your program to be synchronous. await foo()
says to call foo()
, and feel free to go do something else while we're waiting for foo
to return with its answer. Likewise, getting the next element from your custom iterator says "get the next element of this iterator, but feel free to go do something else while waiting for the result". In both cases, you have nothing else to do, so your code wants.
If it is safe for two things in your code to run at once, it is your job to say so, using appropriate primitives.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With