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

Django集成OpenCV出现504超时及Apache卡顿问题排查求助

Django集成OpenCV后请求超时(504 Gateway Timeout)与Apache卡顿问题排查与优化

兄弟,我太懂你这种踩坑的感受了——把CPU密集的CV/OCR逻辑直接塞在同步Django请求里,Apache的工作进程分分钟被堵死,超时、卡顿都是必然结果!咱们一步步拆解问题,给你落地的优化方案:

问题根源分析

你的代码本身逻辑没问题,但犯了Web开发里的经典错误:

  • 同步请求阻塞:Django默认是同步处理请求,get_string里的图像解码、旋转、OCR全是CPU密集型操作,每个请求会占着一个Apache进程不放,并发几个请求服务器直接卡死
  • 不必要的磁盘IO:每次处理都写临时文件再读取,磁盘读写的开销拖慢了整体速度
  • Tesseract调用开销:每次调用image_to_string都会重新初始化Tesseract,启动成本很高

优化方案(按优先级排序)

1. 把CV/OCR移到异步任务队列(最关键)

用Celery+Redis把重计算的活扔到后台,Web服务器只处理轻量的请求转发,彻底解决阻塞问题。

步骤1:安装依赖

pip install celery redis

步骤2:配置Celery(在Django的settings.py里)

CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'

步骤3:创建异步任务(新建tasks.py)

from celery import shared_task
from PIL import Image
import numpy as np
import cv2
import pytesseract

@shared_task
def get_string_task(image_bytes, image_name):
    # 图像解码
    image = np.asarray(bytearray(image_bytes), dtype="uint8")
    image = cv2.imdecode(image, cv2.IMREAD_COLOR)
    
    # 缩小图像尺寸(减少计算量)
    max_dim = 1000
    h, w = image.shape[:2]
    if max(h, w) > max_dim:
        scale = max_dim / max(h, w)
        image = cv2.resize(image, (int(w*scale), int(h*scale)), interpolation=cv2.INTER_AREA)
    
    # 灰度化与反色
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gray = cv2.bitwise_not(gray)
    
    # 阈值处理
    thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    
    # 计算旋转角度
    coords = np.column_stack(np.where(thresh > 0))
    angle = cv2.minAreaRect(coords)[-1]
    if angle < -45:
        angle = -(90 + angle)
    else:
        angle = -angle
    
    # 旋转校正(用更快的INTER_LINEAR插值)
    (h, w) = image.shape[:2]
    center = (w // 2, h // 2)
    M = cv2.getRotationMatrix2D(center, angle, 1.0)
    rotated = cv2.warpAffine(image, M, (w, h), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REPLICATE)
    
    # 再次灰度阈值处理
    gray_rotated = cv2.cvtColor(rotated, cv2.COLOR_BGR2GRAY)
    gray_rotated = cv2.threshold(gray_rotated, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]
    
    # 直接用内存对象给Tesseract,去掉临时文件
    pil_image = Image.fromarray(gray_rotated)
    text = pytesseract.image_to_string(pil_image, lang='spa')
    
    return text

步骤4:修改视图逻辑

from django.http import JsonResponse
from celery.result import AsyncResult
from .tasks import get_string_task

def process_image(request):
    if request.method == 'POST' and request.FILES.get('imagen'):
        imagen = request.FILES['imagen']
        image_bytes = imagen.read()
        # 提交异步任务
        task = get_string_task.delay(image_bytes, imagen.name)
        # 返回任务ID,前端可轮询结果
        return JsonResponse({'task_id': task.id})
    return JsonResponse({'error': 'Invalid request'}, status=400)

# 新增获取任务结果的视图
def get_task_result(request, task_id):
    result = AsyncResult(task_id)
    if result.ready():
        return JsonResponse({'text': result.get()})
    else:
        return JsonResponse({'status': '处理中...'}, status=202)

2. 去掉临时文件IO(已包含在上面的任务里)

原来的代码里写临时文件再读取完全没必要——把OpenCV处理后的numpy数组直接转成PIL Image传给Tesseract,省掉磁盘读写的耗时。

3. 临时优化Apache配置(治标)

如果暂时不想上异步,可以先调整Apache的MPM模块配置,提升并发能力(以mpm_prefork为例):

<IfModule mpm_prefork_module>
    StartServers             8
    MinSpareServers          5
    MaxSpareServers         15
    MaxRequestWorkers       200
    MaxConnectionsPerChild   1000
</IfModule>

但注意:这只是缓解,本质问题还是同步阻塞,高并发下还是会超时。

4. 微调CV操作性能

  • 用cv2.INTER_LINEAR替代cv2.INTER_CUBIC做旋转插值,速度更快,OCR精度足够
  • 预加载Tesseract语言包:确保lang='spa'的语言包已经安装,避免每次调用都下载

最后总结

核心思路就是把CPU密集型操作从Web请求的同步链路中剥离,让Apache只处理轻量的请求转发,重活交给Celery worker去做。配合内存IO优化和CV操作微调,就能彻底解决超时和卡顿问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 13:17:38