You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

命令行运行的Django脚本如何实现请求并行执行?

问题根因

协程代码没有实现并行的核心原因是:requests是同步阻塞HTTP库,在asyncio事件循环中直接调用阻塞IO操作时,会完全占住事件循环的执行权,直到当前请求返回结果之前,事件循环根本没有机会调度其他协程运行。因此哪怕你用asyncio.create_task创建了多个任务,也只能等上一个任务的阻塞请求完全执行完,才会开始跑下一个任务,最终表现为串行执行。

可行解决方案

方案1:使用原生异步HTTP客户端(推荐)

将同步的requests替换为适配asyncio的异步HTTP库(比如aiohttp),这类库在等待IO响应时会主动让出事件循环的执行权,让其他协程可以被调度执行,真正实现异步并发。
修改后的完整可运行代码如下:

import asyncio
import aiohttp
from asgiref.sync import async_to_sync


async def do_task(task, session):
    print(f"starting task {task}")
    async with session.get("https://swapi.dev/api/people/1") as response:
        response_json = await response.json()
        print(response_json)
    print(f"finished task {task}")


async def run():
    # 复用同一个客户端会话,减少连接开销
    async with aiohttp.ClientSession() as session:
        tasks = set()
        for i in range(5):
            task = asyncio.create_task(do_task(i, session))
            tasks.add(task)
            task.add_done_callback(tasks.discard)
        await asyncio.gather(*tasks)


if __name__ in ("__main__", "django.core.management.commands.shell"):
    print("==start==")
    async_to_sync(run)()
    print("==done==")

方案2:将阻塞请求放到线程池执行

如果不想替换现有requests相关逻辑,可以用asyncio.to_thread把阻塞的请求操作放到独立线程中运行,避免阻塞主事件循环,也能实现并发效果。
只需要修改do_task函数即可:

import requests
import asyncio

async def do_task(task):
    print(f"starting task {task}")
    # 把阻塞调用交给线程池执行,不占用事件循环
    response = await asyncio.to_thread(requests.get, "https://swapi.dev/api/people/1")
    response_json = response.json()
    print(response_json)
    print(f"finished task {task}")

注意:该方案依赖线程切换实现并发,性能弱于原生异步实现,仅适合不想大规模修改原有同步代码的临时场景。

运行效果

修改完成后执行脚本,就会先批量打印所有任务的启动日志,再陆续返回接口响应、打印任务完成日志,和预期的输出形式一致。

内容的提问来源于stack exchange,提问作者Android

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 16:45:44