koyamashinji
koyamashinji

Reputation: 635

Asynchronous, Multiple HTTP requests in a While Loop

The code below is intended to send multiple HTTP requests asynchronously in a while loop, and depending on the response from each request(request "X" always returns "XXX", "Y" always returns "YYY" and so on), do something and sleep for interval seconds specified for each request.


However, it throws an error...

RuntimeError: cannot reuse already awaited coroutine

Could anyone help me how I could fix the code to realise the intended behaviour?

class Client:
    def __init__(self):
        pass

    async def run_forever(self, coro, interval):
        while True:
            res = await coro
            await self._onresponse(res, interval)

    async def _onresponse(self, res, interval):
        if res == "XXX":
            # ... do something with the resonse ...
            await asyncio.sleep(interval)
        if res == "YYY":
            # ... do something with the resonse ...
            await asyncio.sleep(interval)
        if res == "ZZZ":
            # ... do something with the resonse ...
            await asyncio.sleep(interval)


async def request(something):
    # ... HTTP request using aiohttp library ...
    return response


async def main():
    c = Client()
    await c.run_forever(request("X"), interval=1)
    await c.run_forever(request("Y"), interval=2)
    await c.run_forever(request("Z"), interval=3)
    # ... and more

Upvotes: 0

Views: 818

Answers (1)

dirn
dirn

Reputation: 20719

As the error says, you can't await a coroutine more than once. Instead of passing a coroutine into run_forever and then awaiting it in a loop, passing the coroutine's argument(s) instead and await a new coroutine each iteration of the loop.

class Client:
    async def run_forever(self, value, interval):
        while True:
            res = await rqequest(value)
            await self._response(response, interval)

You also need to change how you await run_forever. await is blocking, so when you await something with an infinite loop, you'll never reach the next line. Instead, you want to gather multiple coroutines as once.

async def main():
    c = Client()
    await asyncio.gather(
        c.run_forever("X", interval=1),
        c.run_forever("Y", interval=2),
        c.run_forever("Z", interval=3),
    )

Upvotes: 4

Related Questions