-
-
Notifications
You must be signed in to change notification settings - Fork 31k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Odd error awaiting a Future #81353
Comments
Let's start with correct code: import asyncio
async def writer():
await asyncio.sleep(1)
g1.set_result(41)
async def reader():
await g1
async def test():
global g1
g1 = asyncio.Future()
await asyncio.gather(reader(), writer())
asyncio.run(test()) No error, as expected. Now let's mess it up a bit: import asyncio
g1 = asyncio.Future()
async def writer():
await asyncio.sleep(1)
g1.set_result(41)
async def reader():
await g1
async def test():
await asyncio.gather(reader(), writer())
asyncio.run(test()) Fails with RuntimeError ... attached to a different loop The error makes sense, although it's sad that I can't create global futures / there was no even loop when Future was creates, it was not a *different* event loop / maybe I wish .run() didn't force a new event loop? A nit (IMO), but I can live with it. Let's mess the code up a bit more: import asyncio
g1 = asyncio.Future()
async def writer():
await asyncio.sleep(1)
g1.set_result(41)
async def reader():
await g1
async def test():
await asyncio.gather(reader(), reader(), writer())
asyncio.run(test()) RuntimeError: await wasn't used with future What? The actual exception comes from asyncio.Future.__await__ after a yield. |
Global future objects (and global asyncio objects in general) don't work with asyncio.run(). The lifecycle of these objects should be closer than loop but asyncio.run() creates a loop during execution. I think this is a good design, we have a plan to deprecate and eventually drop all old-times mess that allows confusions. All three of your problems are because you use a global future which is implicitly attached to the different loop. Also I'd like to note that futures are low-level API, which is very delicate and error-prone. Futures are crucial for libraries building (e.g. aiohttp uses them a lot) but working with futures in application code is an explicit sign of bad design. |
Dima, unless you want to make a specific doc change suggestion, I think this should be closed. The planned code changes will be on other issues. |
Hi Terry, Yes, I have a specific suggestion: The error |
OK. I am quitting here because asyncio and futures are outside my expertise. |
Not sure what "idempotency fix" means in the context of Future objects. Could you describe desired behavior or, even better, provide a pull request that demonstrates your desire? |
I think that if a Future is abused, the following two should return *same* error: async def test():
await asyncio.gather(reader(), writer()) -vs- async def test():
await asyncio.gather(reader(), reader(), writer()) |
Agree, it would be fine. |
Yes, I think that would be sufficient! I don't know about implementation though, as there's some magic in the way Future.__await__ tries to guess how it was called. I hope one day that magic could go away, but I neither understand the origin nor the mechanics of it, so... My gut tells me that fixing the error involves digging into that magic. |
This is definitely one of the obscure edge cases with mixing global futures and different loop. I checked and this bug is only present in the C implementation so a bug in |
Let's not spend more time on this, the easier way to avoid this is to just avoid using global futures which isn't recommended either. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: