gevent + flask 接口会卡住

部署运行你感兴趣的模型镜像

在使用 geventFlask 处理 CPU 密集型任务时,确实可能会遇到性能瓶颈。这是因为 gevent 主要优化的是 I/O 密集型任务,而不是 CPU 密集型任务。以下是一些可能的原因和解决方案:

原因

  1. Gevent 的协程模型

    • gevent 使用 greenlet 来实现协程,这些协程在单个线程中运行。当一个协程执行 CPU 密集型任务时,它会阻塞整个线程,导致其他协程无法执行。
    • 这会导致 CPU 密集型任务阻塞 I/O 操作,从而降低整体性能。
  2. GIL(全局解释器锁)

    • Python 的 GIL 限制了同一时间只能有一个线程执行 Python 字节码。即使你使用 gevent,GIL 仍然会限制 CPU 密集型任务的并行性。

解决方案

  1. 多进程

    • 对于 CPU 密集型任务,可以使用多进程来绕过 GIL 的限制。你可以使用 multiprocessing 模块来启动多个进程,每个进程独立运行,从而提高 CPU 利用率。
    • 示例代码:
      from flask import Flask
      from multiprocessing import Process, Queue
      
      app = Flask(__name__)
      
      def cpu_bound_task(q):
          # 模拟 CPU 密集型任务
          result = 0
          for i in range(10**7):
              result += i
          q.put(result)
      
      @app.route('/cpu_bound')
      def cpu_bound():
          q = Queue()
          p = Process(target=cpu_bound_task, args=(q,))
          p.start()
          p.join()
          result = q.get()
          return f"Result: {result}"
      
      if __name__ == '__main__':
          app.run()
      
  2. 使用异步任务队列

    • 对于 CPU 密集型任务,可以使用异步任务队列(如 Celery)来将任务分发到多个 worker 进程中执行。
    • 示例代码:
      from flask import Flask
      from celery import Celery
      
      app = Flask(__name__)
      celery = Celery(app.name, broker='redis://localhost:6379/0')
      
      @celery.task
      def cpu_bound_task():
          # 模拟 CPU 密集型任务
          result = 0
          for i in range(10**7):
              result += i
          return result
      
      @app.route('/cpu_bound')
      def cpu_bound():
          result = cpu_bound_task.delay()
          return f"Task ID: {result.id}"
      
      if __name__ == '__main__':
          app.run()
      
  3. 使用异步框架

    • 如果你需要处理大量并发请求,尤其是 I/O 密集型任务,可以考虑使用异步框架(如 FastAPI)来替代 Flask。FastAPI 基于 asyncio,能够更好地处理并发请求。

总结

  • 对于 CPU 密集型任务,geventFlask 的组合可能会遇到性能瓶颈。
  • 解决方案包括使用多进程、异步任务队列(如 Celery)或切换到更适合处理并发请求的异步框架(如 FastAPI)。

通过这些方法,你可以更好地处理 CPU 密集型任务,避免性能瓶颈。

您可能感兴趣的与本文相关的镜像

Python3.9

Python3.9

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

# -*- coding: utf-8 -*- import sys import io import tempfile import os import time from flask import Flask, request, jsonify from flask_cors import CORS from rapidocr_onnxruntime import RapidOCR from pdf2image import convert_from_bytes, pdfinfo_from_bytes from PIL import Image # 强制系统使用UTF-8编码 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') app = Flask(__name__) CORS(app) # 关键配置:禁用JSON的ASCII转码 app.config['JSON_AS_ASCII'] = False # Flask<2.3版本 app.json.ensure_ascii = False # Flask>=2.3版本 # 添加文件大小限制(50MB) app.config['MAX_CONTENT_LENGTH'] = 50 * 1024 * 1024 engine = RapidOCR() ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'bmp', 'pdf'} def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS def process_pdf_to_text(pdf_bytes, dpi=200, timeout=300): """ 处理PDF文件并返回所有页面的文本 :param pdf_bytes: PDF文件的字节数据 :param dpi: 图像分辨率(默认为200 DPI) :param timeout: 处理超时时间(秒) :return: 合并后的文本字符串 """ start_time = time.time() full_text = [] # 获取PDF信息(页数) pdf_info = pdfinfo_from_bytes(pdf_bytes) page_count = pdf_info["Pages"] print(f"PDF包含{page_count}页") # 转换PDF为图片序列(分页处理) for page_num in range(1, page_count + 1): # 检查处理时间是否超时 if time.time() - start_time > timeout: raise TimeoutError("PDF处理超时") # 只转换当前单页减少内存占用 images = convert_from_bytes( pdf_bytes, dpi=dpi, first_page=page_num, last_page=page_num, fmt='jpeg' ) if not images: print(f"第{page_num}页转换失败") continue print(f"处理第{page_num}/{page_count}页") image = images[0] # 使用临时文件处理图像 with tempfile.NamedTemporaryFile(suffix='.jpg', delete=True) as temp_img: image.save(temp_img.name, 'JPEG') # 调用OCR引擎 ocr_result, _ = engine(temp_img.name) # 提取本页文本 page_text = [item[1] for item in ocr_result] full_text.append(f"\n--- 第 {page_num} 页 ---\n") full_text.append("\n".join(page_text)) return "\n".join(full_text) @app.route('/ocr', methods=['POST']) def ocr_processing(): if 'file' not in request.files: return jsonify({'error': '未上传文件'}), 400 file = request.files['file'] if file.filename == '': return jsonify({'error': '未选择文件'}), 400 if not allowed_file(file.filename): return jsonify({'error': '不支持的文件格式'}), 400 file_ext = file.filename.rsplit('.', 1)[1].lower() try: # 处理PDF文件 if file_ext == 'pdf': with tempfile.NamedTemporaryFile(delete=True) as temp_file: file.save(temp_file.name) with open(temp_file.name, 'rb') as f: pdf_bytes = f.read() result_text = process_pdf_to_text(pdf_bytes) response = jsonify({ 'result': result_text, # 'file_type': 'pdf', # 'page_count': pdfinfo_from_bytes(pdf_bytes)["Pages"] }) # 处理图片文件(原始逻辑) else: with tempfile.NamedTemporaryFile(delete=False) as temp_file: file.save(temp_file.name) result, elapse = engine(temp_file.name) os.unlink(temp_file.name) formatted_result = [{ 'text': item[1], # 'confidence': float(item[2]), # 'coordinates': item[0] } for item in result] response = jsonify({ 'result': formatted_result, 'processing_time': elapse, 'file_type': 'image' }) response.headers['Content-Type'] = 'application/json; charset=utf-8' return response except TimeoutError as te: return jsonify({'error': str(te), 'tip': '请尝试拆分PDF或降低分辨率'}), 500 except Exception as e: error_msg = str(e) print(f"处理错误: {error_msg}") return jsonify({'error': error_msg}), 500 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) 上传pdf的页数过多终端会提示172.19.0.3 - - [09/Jun/2025 09:16:48] "POST /ocr HTTP/1.1" 500 -,测试提示超时,这个服务也会卡掉,请帮我优化代码。上传60页左右的pdf也可以正常识别文字。
06-10
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

颹蕭蕭

白嫖?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值