Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

On the 2nd iteration of loop Python throws error "RuntimeWarning: coroutine 'to_thread' was never awaited"

I have one "parent" sync function and one "child" sync function. I want to run few "child" functions as a result I convert them to coroutine. Child functions/coroutines I run inside loop – for some reason the 1st loop returns result, but the 2nd one throws RuntimeWarning: coroutine 'to_thread' was never awaited

Minimal code:

import asyncio


def some_func(number):
    print('task number:', number)
    return number


def start():
    for r in range(2):
        print('r:', r)

        tasks = []

        for i in range(5):
            tasks.append(asyncio.to_thread(some_func, i))

        responses = asyncio.gather(*tasks, return_exceptions=True)
        loop = asyncio.get_event_loop()
        results = loop.run_until_complete(responses)
        loop.close()

        print('results:', results)


if __name__ == '__main__':
    start()

Result:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

r: 0
task number: 0
task number: 1
task number: 2
task number: 3
task number: 4
results: [0, 1, 2, 3, 4]
r: 1
Traceback (most recent call last):
  File "/media/antonio/www/tourbase/booking-system/back-end/arctic_reservations/src/test.py", line 27, in <module>
    start()
  File "/media/antonio/www/tourbase/booking-system/back-end/arctic_reservations/src/test.py", line 18, in start
    responses = asyncio.gather(*tasks, return_exceptions=True)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/tasks.py", line 827, in gather
    fut = _ensure_future(arg, loop=loop)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/tasks.py", line 680, in _ensure_future
    return loop.create_task(coro_or_future)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/asyncio/base_events.py", line 434, in create_task
    self._check_closed()
  File "/usr/lib/python3.11/asyncio/base_events.py", line 519, in _check_closed
    raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
sys:1: RuntimeWarning: coroutine 'to_thread' was never awaited

If I put loop = asyncio.get_event_loop() and loop.close() outside of for loop, everything is ok.

Could anybody explain why it happens? As I understand, the 2nd loop should create a new event loop.

Python v3.11.6

>Solution :

At the end of the first iteration, you closed the event loop.

As I understand, the 2nd loop should create a new event loop.

No, get_event_loop returns the existing event loop. When you try to submit new tasks to it in the second iteration, it tells you that you cannot do this because it is already closed.

The function that always creates a new event loop is called new_event_loop.

But instead of trying to manage multiple event loops yourself by asyncio.get_event_loop and loop.run_until_completed and loop.close, you can simply use a single event loop which asyncio.run handles for you automatically (start needs to become a coroutine):

import asyncio


def some_func(number):
    print('task number:', number)
    return number


async def start():
    for r in range(2):
        print('r:', r)

        tasks = []

        for i in range(5):
            tasks.append(asyncio.to_thread(some_func, i))

        results = await asyncio.gather(*tasks, return_exceptions=True)
        print('results:', results)


if __name__ == '__main__':
    asyncio.run(start())
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading