Reputation: 566
I'm using a simple context manager with an asyncio loop inside:
class Runner:
def __init__(self):
self.loop = asyncio.get_event_loop()
def __enter__(self):
return self
def __exit__(self, *args):
self.loop.close()
def do_work(self):
...
return self.loop.run_until_complete(asyncio.gather(*futures))
When I use two Runner objects, I get "Coroutine was never awaited" error.
with Runner() as r:
r.do_work()
with Runner() as r2:
r2.do_work()
Because a loop was closed in the first Runner(r). Everything works if I don't close a loop in exit, but I don't need to keep it opened. I know that we can have only one loop in a thread, but why it doesn't wait for run_until_complete?
Upvotes: 3
Views: 10755
Reputation: 39516
why it doesn't wait for run_until_complete
Probably something like this happens:
import asyncio
async def test():
await asyncio.sleep(0.1)
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(test())
loop.close()
loop.run_until_complete(test())
Result:
RuntimeError: Event loop is closed
sys:1: RuntimeWarning: coroutine 'test' was never awaited
Since you're using event loop this way, you can just use new event loop each time:
class Runner:
def __init__(self):
self.loop = asyncio.new_event_loop() # *new*_event_loop
def do_work(self):
# Make sure all futures are created
# with relevant event loop been set as current
asyncio.set_event_loop(self.loop)
# ...
return self.loop.run_until_complete(asyncio.gather(*futures))
Upvotes: 4