Python中如何优化Django并发下载图片的性能

我想问问我的 django 框架 在服务器 5m 网址 20 并发时获取 500kb,使用 fileresponse 返回图片是,平均获取 10s,这个怎么优化

服务器配置:阿里云 cpu 8 核 内存 32g 网速 5m


Python中如何优化Django并发下载图片的性能
4 回复

图片很大? 5M 的网 500K 速度差不多也快到头了


这个问题我遇到过。Django处理并发下载图片性能瓶颈主要在I/O等待上,用同步请求会阻塞整个进程。

核心思路是把同步阻塞改成异步非阻塞。我推荐用aiohttp配合asyncio,这样可以在单个线程里并发处理多个下载请求。

import aiohttp
import asyncio
from django.http import JsonResponse
from django.views import View
import os

class AsyncDownloadView(View):
    async def get(self, request):
        image_urls = request.GET.getlist('urls')  # 获取多个图片URL
        
        if not image_urls:
            return JsonResponse({'error': 'No URLs provided'}, status=400)
        
        # 并发下载所有图片
        images_data = await self.download_images_concurrently(image_urls)
        
        # 这里可以添加保存到本地或数据库的逻辑
        # save_images_locally(images_data)
        
        return JsonResponse({
            'downloaded_count': len(images_data),
            'total_urls': len(image_urls)
        })
    
    async def download_images_concurrently(self, urls):
        """并发下载多个图片"""
        async with aiohttp.ClientSession() as session:
            tasks = [self.fetch_image(session, url) for url in urls]
            results = await asyncio.gather(*tasks, return_exceptions=True)
        
        # 过滤掉下载失败的(返回异常的)
        return [result for result in results if not isinstance(result, Exception)]
    
    async def fetch_image(self, session, url):
        """下载单个图片"""
        try:
            async with session.get(url, timeout=10) as response:
                if response.status == 200:
                    return {
                        'url': url,
                        'data': await response.read(),
                        'content_type': response.headers.get('Content-Type', '')
                    }
                return None
        except Exception as e:
            print(f"Failed to download {url}: {e}")
            return None

# 在urls.py中配置
# from django.urls import path
# from .views import AsyncDownloadView
# 
# urlpatterns = [
#     path('download-images/', AsyncDownloadView.as_view(), name='download_images'),
# ]

关键点:

  1. asyncio.gather()同时发起所有下载请求,而不是一个个顺序下载
  2. aiohttp的异步HTTP客户端不会阻塞事件循环
  3. 设置合理的超时时间避免长时间等待

如果图片数量特别大,可以考虑分批处理,比如每批50个URL,用asyncio.Semaphore控制并发数。

另外,如果下载的图片需要保存,建议用异步文件操作库如aiofiles,避免阻塞在磁盘I/O上。

用异步的方式能让你的Django应用在等待网络响应时继续处理其他请求,显著提升并发性能。

总结:用异步非阻塞代替同步阻塞。

下载图片用 Nginx 等 Web 代理取代,资源安全性通过动态修改文件名实现。

是静态图片么?
理论上说根本不应该让 django 来做提供静态图片的服务。
应该直接用 Nginx 直接来处理静态图片。最好直接用阿里云的 OSS 打开静态网站功能,还能开启 CDN 加速。

回到顶部