I have a local Django project and some scripts that execute requests in parallel, but the requests are always executed synchronously.
Here is a sample script that demonstrates the issue:
import asyncio
import json
import requests
from asgiref.sync import async_to_sync
async def do_task(task):
print(f"starting task {task}")
response = requests.get("https://swapi.dev/api/people/1")
response_json = json.loads(response.text)
print(response_json)
print(f"finished task {task}")
async def run():
tasks = set()
for i in range(5):
task = asyncio.create_task(do_task(i))
tasks.add(task)
task.add_done_callback(tasks.discard)
await asyncio.gather(*tasks)
# python manage.py shell < path/to/scripts/test.py
if __name__ in ("__main__", "django.core.management.commands.shell"):
print("==start==")
async_to_sync(run)()
print("==done==")
The output for this script is:
==start==
starting task 0
{...} # response
finished task 0
starting task 1
{...} # response
finished task 1
starting task 2
{...} # response
finished task 2
starting task 3
{...} # response
finished task 3
starting task 4
{...} # response
finished task 4
==done==
I would expect to see something closer to this (all tasks started at the same time):
==start==
starting task 0
starting task 1
starting task 2
starting task 3
starting task 4
{...} # response
{...} # response
{...} # response
{...} # response
{...} # response
finished task 0
finished task 1
finished task 2
finished task 3
finished task 4
==done==
requests blocks the main thread, similar to using timer.sleep
instead of asyncio.sleep
.
Using aiohttp solves the issue.
Thanks @dirn for the help!
import asyncio
import json
import aiohttp
from asgiref.sync import async_to_sync
async def do_task(task):
print(f"starting task {task}")
async with aiohttp.ClientSession() as session:
async with session.get("https://swapi.dev/api/people/1") as response:
response_json = json.loads(await response.text())
print(response_json)
print(f"finished task {task}")
async def run():
tasks = set()
for i in range(10):
task = asyncio.create_task(do_task(i))
tasks.add(task)
task.add_done_callback(tasks.discard)
await asyncio.gather(*tasks)
# python mainsite/manage.py shell < mainsite/funds/scripts/test.py
if __name__ in ("__main__", "django.core.management.commands.shell"):
print("==start==")
async_to_sync(run)()
print("==done==")