1

Is a loop.close() needed prior to returning async values in the below code?

import asyncio

async def request_url(url):
    return url

def fetch_urls(x):
    loop = asyncio.get_event_loop()
    return loop.run_until_complete(asyncio.gather(*[request_url(url) for url in x]))

That is, should fetch_urls be like this instead?:

def fetch_urls(x):
    loop = asyncio.get_event_loop()
    results = loop.run_until_complete(asyncio.gather(*[request_url(url) for url in x]))
    loop.close()
    return results

If the loop.close() is needed, then how can fetch_urls be called again without raising the exception: RuntimeError: Event loop is closed?

A previous post states that it is good practice to close the loops and start new ones however it does not specify how new loops can be opened?

Greg
  • 8,175
  • 16
  • 72
  • 125
  • For completeness's sake, you can start a new event loop by call `asyncio.new_event_loop()`. – dirn Mar 06 '17 at 21:43

2 Answers2

2

You can also keep the event loop alive, and close it the end of your program, using run_until_complete more than once:

import asyncio


async def request_url(url):
    return url


def fetch_urls(loop, urls):
    tasks = [request_url(url) for url in urls]
    return loop.run_until_complete(asyncio.gather(*tasks, loop=loop))


loop = asyncio.get_event_loop()
try:
    print(fetch_urls(loop, ['a1', 'a2', 'a3']))
    print(fetch_urls(loop, ['b1', 'b2', 'b3']))
    print(fetch_urls(loop, ['c1', 'c2', 'c3']))
finally:
    loop.close()
Udi
  • 29,222
  • 9
  • 96
  • 129
1

No, the async function (request in this case) should not be closing the event loop. The command loop.run_until_complete will close stop the event loop as soon as it runs out of things to do.

fetch_urls should be the second version -- that is, it will get an event loop, run the event loop until there is nothing left to do, and then closes it loop.close().

Ethan Furman
  • 63,992
  • 20
  • 159
  • 237