Как распараллелить запросы в скрипте django, запущенном из командной строки?

У меня есть локальный проект Django и несколько скриптов, которые выполняют запросы параллельно, но запросы всегда выполняются синхронно.

Вот пример сценария, который демонстрирует проблему:

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==")

Вывод для этого сценария следующий:

==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==

Я бы ожидал увидеть что-то близкое к этому (все задачи запускаются в одно и то же время):

==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==

запросы блокируют основной поток, аналогично использованию timer.sleep вместо asyncio.sleep.

Использование aiohttp решает проблему.

Спасибо @dirn за помощь!

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==")
Вернуться на верх