深入探讨 Flask、Gunicorn、Gevent 与 RecursionError:事件循环与 Monkey Patching 的正确使用

在现代高并发应用中,使用异步 I/O 操作处理密集的网络任务(例如短信发送)是提升系统性能的常见策略。为了在 Python 中实现这样的并发处理,我们可以使用 Gunicorn 和 Gevent 搭配 Flask 应用。然而,在实现过程中,开发者可能会遇到 递归错误(RecursionError),这主要源于 monkey patching 的时机问题。本文将详细分析这一现象的根源以及解决方案。

背景与应用场景

我们需要构建一个异步的 Flask 应用,它可以通过阿里云短信服务发送验证码,并将验证码存储到 Redis 进行校验。为了提升性能并发能力,我们选择了以下技术栈:

  • Flask:轻量级的 Python Web 框架。
  • Gunicorn:WSGI 服务器,用于在生产环境中运行 Flask。
  • Gevent:用于异步协程的库,能够让 Python 应用在 I/O 密集型任务中表现更优异。

Gevent 与 Gunicorn 的工作原理

1. Gevent 与 Gunicorn 如何协同工作

Gevent 是基于协程的,并且提供了 monkey patching 功能,通过它可以将 Python 标准库中的阻塞操作(如 socketssltime 等)替换为非阻塞的实现。这样,Gevent 便可以通过轻量级的绿色线程(Greenlet)并发处理任务。

当我们在 Gunicorn 中设置 worker_class = "gevent" 时,Gunicorn 会自动使用 Gevent 来管理并发请求,进而达到提高系统吞吐量的目的。这个配置会在 初始化工作进程时 调用 monkey.patch_all(),将所有可能导致阻塞的操作转换为非阻塞操作。

2. Gunicorn 配置中的 Gevent
 
# gunicorn_conf.py
from gevent import monkey
monkey.patch_all()  # 在启动时将所有阻塞操作替换为非阻塞操作
from flask import Flask# Gunicorn的工作进程数,通常设置为CPU核心数的2倍
workers = 4# 使用 gevent 的异步 worker 类
worker_class = "gevent"# 超时时间
timeout = 120# 绑定端口
bind = "0.0.0.0:5100"

在这里,monkey.patch_all() 会在 Gunicorn worker 初始化时被调用,从而确保整个应用能够处理异步 I/O 请求。

3. Monkey Patching 的概念

Monkey Patching 是在运行时修改或替换模块或类的行为。在 Gevent 中,monkey.patch_all() 会将标准库中的阻塞操作(例如 socketssl)替换为非阻塞操作。这使得 Gevent 可以通过轻量级线程来异步执行这些 I/O 操作,而不需要阻塞主线程。

from gevent import monkey
monkey.patch_all()  # 在启动时替换所有可能导致阻塞的操作

递归错误(RecursionError)的根源

在我们的应用中,当 Gunicorn 使用 Gevent 时,我们可能遇到了一个经典问题——递归错误
 

RecursionError: maximum recursion depth exceeded while calling a Python object

这个问题的原因:递归错误发生的原因通常是因为在导入了 ssl 或其他 I/O 模块之后,才调用了 monkey.patch_all()。由于 Gevent 尝试将已经导入的阻塞操作(如 ssl)进行替换,导致递归调用,从而引发递归深度超限。

Gunicorn 的 worker_class = "gevent" 会在启动时自动调用 monkey.patch_all()。因此,如果你的应用在启动时已经导入了 ssl 或其他模块,Gevent 再次尝试 monkey-patch 这些模块时,就会引发递归错误。

如何避免递归错误

1. 手动控制 Monkey Patching 的时机

要避免递归错误,你需要确保 monkey.patch_all() 在所有 I/O 模块(如 ssl)导入之前执行。可以将 monkey.patch_all() 移到程序的最前面,在导入其他模块之前执行。
 

from gevent import monkey
monkey.patch_all()  # 确保最早执行from flask import Flask
app = Flask(__name__)
2. 禁用部分模块的 Monkey Patching

如果你不需要 Gevent 对某些模块(如 ssl)进行 patch,可以使用 monkey.patch_all() 的参数来禁用它。例如:

from gevent import monkey
monkey.patch_all(ssl=False)  # 禁用 ssl 的 monkey-patch

这样,Gevent 不会对 ssl 模块进行替换,从而避免递归错误。

3. 避免重复 Monkey Patching

在某些情况下,你可能已经在 Gunicorn 中配置了 worker_class = "gevent",并且显式调用了 monkey.patch_all()。此时不需要再次调用 monkey.patch_all()。确保只调用一次 patch 操作,避免递归错误。

总结

在使用 Gevent 和 Gunicorn 构建异步 Flask 应用时,递归错误通常是由于 Monkey Patching 的时机不当引发的。为了避免这种错误:

  • 确保在程序启动时 最早 执行 monkey.patch_all()
  • 如果你不需要对某些模块(如 ssl)进行 patch,可以禁用这些模块的 monkey-patch。
  • 如果已经在 Gunicorn 中启用了 Gevent worker,避免在代码中再次手动调用 monkey.patch_all()

通过合理地管理 Gevent 的 monkey-patching,我们可以构建一个高效、可靠的异步 Flask 应用,能够更好地处理高并发请求和 I/O 密集型任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/145070.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【machine learning-十-grading descent梯度下降实现】

grading descent 梯度下降参数更新方法 --导数和学习率 从导数项直观理解梯度下降 grading descent 算法就是更新参数,今天来学习下如何更新w和b 梯度下降 还是以线性回归的均方差损失函数如下为例: 损失函数的可视化图如下 : 横轴和纵轴分…

影刀RPA实战:网页爬虫之苦瓜书籍数据

书籍常常被视为心灵的慰藉,因为它们能够在不同的层面上为人们提供支持和安慰。 1. 书籍对我们的重要性 书籍是人类知识的载体,也是智慧的结晶。它们不仅是学习的工具,更是人类心灵的慰藉。在忙碌的生活中,书籍能够提供知识、启发…

魅思CMS getOrderStatus SQL注入漏洞复现

0x01 漏洞描述: 魅思是一款集成了视频管理、用户管理、手机端应用封装等功能的综合性视频管理系统。该系统不仅以其强大的视频管理功能、灵活的用户管理机制、便捷的手机端应用封装功能以及高安全性和现代化的界面设计,成为了市场上备受关注的视频管理系…

技术美术百人计划 | 《4.5 DOF景深算法》笔记

1. 景深定义 景深(Depth of Field,DOF),是指在摄影机镜头或其他成像器前沿能够取得清晰图像的成像所测定的被摄物体前后距离范围。镜头光圈、镜头焦距、及焦平面到拍摄物的距离是影响景深的重要因素。在聚焦完成后,焦点…

监控IDS和IPS增强网络安全性

入侵检测系统(IDS)和入侵防御系统(IPS)是当今使用的最复杂的网络安全设备之一,它们检查网络数据包并阻止可疑数据包,并提醒管理员有关攻击企图的信息。 在当今威胁不断变化的网络环境中,防火墙…

TopoDOT2024.1注册机 道路自动化提取 雷达点云数据

TopoDOT2024.1是一套成熟的点云数据处理及应用系统,全面具备点云数据的存储管理、精度检核、特征自动提取、智能分析、高效建模、成果输出等应用功能。TopoDOT在LiDAR数据应用领域有着多年的实战经验,用户在实际项目中长期使用,尤其在交通领域…

iOS 巨魔神器,Geranium 天竺葵:6大功能,个个都解决痛点

嘿,这是黑猫。如果你装了巨魔,却只知道安装第三方APP,那就是暴殄天物。巨魔的价值不仅是应用侧载,还有强大的玩机工具生态——这也是我花费大量时间,去制作巨魔精选IPA合集的原因。 通过巨魔商店安装的APP&#xff0c…

初学者的鸿蒙多线程并发之 TaskPool 踩坑之旅

1. 背景 目标群体:鸿蒙初学者 版本:HarmonyOS 3.1/4.0 背景:鸿蒙 App 的全局路由管理功能,需要在 App 启动时初始化对 raw 下的相关配置文件进行读取、解析并缓存。App 启动时涉及到了大量模块的初始化,好多模块都涉…

智能绘画Midjourney AIGC在设计领域中的应用

科技的进步,人工智能(AI)正以前所未有的方式渗透进各个领域,尤其是在艺术创作,尤其是绘画。Midjourney作为AI绘画技术的代表,其AIGC(Artificial Intelligence for Generative Content&#xff0…

python SQLAlchemy 数据库连接池

文章目录 前言python SQLAlchemy 数据库连接池1. 安装2. 创建数据库引擎3. 新建表,增删改查demo 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。   而且听说点赞的人每天的运气都…

【Linux】—— muduo网络库的安装配置与使用

muduo网络库编程 Linux环境下Epollpthread线程库 Boost库安装与使用 安装Boost库 下载boost库源码,linux环境解压 tar -zxvf boost_1_69_0.tar.gz 解压完成后,进入该目录,查看内容 运行bootstrap.sh工程编译构建程序 ./bootstrap.sh …

JAVA同城生活新引擎外卖跑腿团购到店服务多合一高效系统小程序源码

🚀同城生活新风尚!一站式高效系统,让日常更便捷🛍️ 🍽️【开篇:同城生活,一触即发】🍽️ 在这个快节奏的时代,同城生活的便利性与效率成为了我们追求的新风尚。想象一下…

C# 从字符串中分离文件路径、文件名及扩展名

C# 从字符串中分离文件路径、文件名及扩展名 对文件进行操作时,首先要获取文件路径信息,然后创建文件对象,通过IO流将数据读取大宋内存中并进行处理。在操作文件时,可能还需要提取文件的一些信息,比如,文件…

有效安全计划评估的基本指标

衡量安全计划成功与否的最有效指标是什么? 最直接的指标是:您的组织是否遭到入侵?如果答案是肯定的,那么显然还有工作要做。如果答案是否定的,那么您的状况就更好了——但情况比这更复杂。 即使您没有遭到入侵&#…

SonarWiz 8.0.1注册机 全模块版本侧扫、浅剖、测深软件功能等

SonarWiz 8.0.1是功能强大的测绘软件!提供强大的数据采集、后处理等功能操作,您将获得灵活完整的报告,并提供丰富的选项以便进行定制和更灵活的进行操作,软件功能齐全,包括完整的海底测绘解决方案,方便实时…

chapter15-泛型——(自定义泛型)——day20

目录 561-自定义泛型类 562-自定义泛型接口 563-自定义泛型方法 泛型就是可以接受一种数据类型的类型 564-泛型方法练习 565-泛型继承和通配 566-JUnit使用 568-泛型家庭作业 561-自定义泛型类 562-自定义泛型接口 563-自定义泛型方法 泛型就是可以接受一种数据类型的类型…

数据结构(Day16)

一、学习内容 1、有关顺序表的操作(功能函数) 1、创建顺序表 Plist create_list(){Plist L malloc(sizeof(list)); // 为顺序表分配内存空间if(NULL L){printf("申请空间失败\n");return NULL; // 如果内存分配失败,返回 NU…

node发送邮件:如何实现Node.js发信功能?

node发送邮件及附件方法?如何用nodejs自动发送邮件? 无论是用于用户注册确认、密码重置,还是用于发送通知和报告,Node发送邮件功能都是非常有用的。AokSend将详细介绍如何使用Node.js实现发信功能,帮助你掌握这一重要…

kubernetes存储之GlusterFS(GlusterFS for Kubernetes Storage)

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

虚拟机的ip总是自己变化如何解决?

目录 修改配置文件: 如果出现错误E212:无法打开并写入文件: 如果显示当前用户没有在sudoers文件中,就按照下面方法操作。 修改配置文件: 变化的原因:在配置文件/etc/sysconfig/network-scripts/ifcfg-e…