Python Flask API无法处理多请求,寻求技术排查指导
问题排查与解决方案
你的问题核心是单个请求的OCR处理就耗尽了系统全部线程,叠加多请求后,Flask线程池+OCR线程完全占满CPU,导致系统无响应、资源枯竭。以下是具体的排查和解决方向:
1. 限制OCR的并发线程数
不要让OCR引擎直接占用全部可用线程,手动控制并发数:
- 用
concurrent.futures.ThreadPoolExecutor封装OCR任务,设置合理的max_workers,比如取CPU核心数的1/2到2/3(避免单个请求占满资源)。示例代码:
import concurrent.futures import os def ocr_single_page(image): # 单个页面的OCR逻辑 pass def ocr_all_pages(images): max_workers = os.cpu_count() // 2 # 比如用一半核心 with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: results = list(executor.map(ocr_single_page, images)) return results
- 如果你的OCR引擎(如Tesseract)自带线程参数,直接设置对应参数(比如Tesseract的
--threads),不要让它默认占用全部线程。
2. 替换Flask开发服务器为生产级WSGI服务器
Werkzeug(Flask自带服务器)的threaded=True没有线程数限制,生产环境下无法有效控制资源,换成Gunicorn或uWSGI:
- 用Gunicorn启动,控制进程和线程数:
gunicorn --workers 2 --threads 4 --timeout 300 app:app -b 0.0.0.0:6996
--workers:进程数,一般设为CPU核心数或核心数+1--threads:每个进程的线程数,结合OCR线程数,控制总线程数不超过系统承载能力--timeout:延长超时时间,适配长任务
3. 引入异步任务队列解耦请求与处理
把OCR和深度学习模型处理放到异步任务中,避免请求长时间阻塞Flask线程:
- 用Celery+Redis作为任务队列:
- 配置Celery连接Redis
- 把OCR+模型处理逻辑封装为Celery任务
- Flask只负责接收PDF、提交任务,返回任务ID给客户端
- 客户端通过任务ID轮询获取处理结果
- 好处:可通过Celery的worker数控制并发任务数,避免资源瞬间占满,同时Flask能快速响应请求,不会被长任务阻塞。
4. 定位资源瓶颈
- 用
htop观察CPU占用:如果OCR阶段CPU拉满,重点优化OCR并发数;如果模型推理阶段占比高,考虑:- 改用GPU加速模型推理(若当前用CPU)
- 限制模型并发数(比如同一时间只允许1-2个推理任务)
- 复用模型实例,避免每次请求重新加载模型(模型加载极耗资源)
- 用
free -m监控内存,排查是否存在内存泄漏或内存不足的情况。
5. 优化任务流程
- PDF转图像时,在不影响OCR精度的前提下,降低图像分辨率、灰度化,减少OCR计算量
- 简化文本清洗逻辑,避免不必要的字符串操作或正则匹配
- 若多个深度学习模型可并行处理,用多进程(而非多线程,Python GIL限制下CPU密集型任务多进程更高效)处理,但需严格控制并发数
内容的提问来源于stack exchange,提问作者spectre
相关产品推荐
相关产品推荐

