'Send asynchronous HTTP requests one after another

I am trying to use aiohttp to send requests one after another like this

import aiohttp
import asyncio
from datetime import datetime


async def main():
    request_url = "https://..."
    async with aiohttp.ClientSession() as session:
        while True:
            print(datetime.now())
            async with session.get(request_url) as response:
                json_data = await response.json()
            print(json_data)
            await asyncio.sleep(0.2)


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

So I would expect each datetime print to be 0.2s apart. However, they seem to be about 0.35s apart as I think it takes 0.15s to get the data from the response. Why is this happening? I want it to be asynchronous so it should just go onto the next one?

How can I fix this?



Solution 1:[1]

When you use await all next code will wait for end of this code. If you want to run asyncio code asynchronously, you should use functions like asyncio.gather


import asyncio
import aiohttp
import datetime


async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            print('#', response.status)


async def worker(queue):
    print('START WORKER')
    while True:
        url = await queue.get()
        await fetch(url)
        queue.task_done()


async def control(queue):
    while True:
        print(datetime.datetime.now())
        queue.put_nowait('https://docs.python.org/')
        await asyncio.sleep(0.2)


async def main():
    queue = asyncio.Queue()
    await asyncio.gather(
        control(queue),
        asyncio.gather(*[worker(queue) for _ in range(10)])
    )


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Solution 2:[2]

Sending http request and fetching response back takes some time. You need excluding this time from asyncio.sleep() call:

import aiohttp
import asyncio
import time
from datetime import datetime


async def main():
    request_url = "https://..."
    async with aiohttp.ClientSession() as session:
        while True:
            print(datetime.now())
            t0 = time.monotonic()
            async with session.get(request_url) as response:
                json_data = await response.json()
            print(json_data)
            t1 = time.monotonic()
            await asyncio.sleep(0.2 - (t1 - t0))


if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Andrew Svetlov