Home > Back-end >  Passing in a list of functions to asyncio.gather()
Passing in a list of functions to asyncio.gather()

Time:02-23

from aiohttp import ClientSession
import asyncio
import threading
import time     

 class Query():

    def execute_async(self):
    asyncio.run(self.call_requests())

    async def call_requests(self):
        self.api_request_list = []

        self.PROMETHEUS_URL = "http://www.randomnumberapi.com/api/v1.0/random?min=100&max=1000&count=1"

        self.api_request_list.append(self.api_request(self.PROMETHEUS_URL, 1))
        self.api_request_list.append(self.api_request(self.PROMETHEUS_URL, 1))
        self.api_request_list.append(self.api_request(self.PROMETHEUS_URL, 1))

        while True:
            timer_start = time.perf_counter()

            await asyncio.gather(*self.api_request_list)

            timer_stop = time.perf_counter()
            print(f"Performed all requests in... {timer_stop - timer_start:0.4f} seconds")

    async def api_request(self, query, sleep_duration):
        await asyncio.sleep(sleep_duration)
        async with ClientSession() as session:
            async with session.get(self.PROMETHEUS_URL) as response:
            response = await response.text()
            random_int = int(response[2])
            print('Request response... {0}'.format(random_int))

if __name__ == '__main__':
    query = Query()

The api_request_list should hold a list of functions. This list of functions should be passed into asyncio.gather.

I am currently getting the following error message:

RuntimeError: cannot reuse already awaited coroutine

CodePudding user response:

That's not a list of functions. asyncio.gather doesn't take a list of functions.

What you have there is a list of coroutine objects. Calling an async function produces a coroutine object, which holds the state of the async function call's execution.

When you pass the list to asyncio.gather a second time, all the coroutines are already finished. You're telling asyncio.gather "run these coroutines", and asyncio.gather is telling you "I can't do that - they already ran".

If you want to run an async function again, you need to call it again. You can't keep using the old coroutine objects. That means you need to populate the list inside the loop:

while True:
    api_request_list = [
        self.api_request(self.PROMETHEUS_URL, 1),
        self.api_request(self.PROMETHEUS_URL, 1),
        self.api_request(self.PROMETHEUS_URL, 1),
    ]

    timer_start = time.perf_counter()

    await asyncio.gather(*api_request_list)

    timer_stop = time.perf_counter()
    print(f"Performed all requests in... {timer_stop - timer_start:0.4f} seconds")
  • Related