gevent 为什么打了猴子补丁 还是会出现无限递归错误? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Ritter

gevent 为什么打了猴子补丁 还是会出现无限递归错误?

  •  
  •   Ritter 2020 年 3 月 12 日 4280 次点击
    这是一个创建于 2235 天前的主题,其中的信息可能已经有所发展或是发生改变。

    环境是 Flask + Gunicorn + gevent
    已经在入口函数打了 monkey patch
    可是在别的文件调用 requests 方法还是会报无限递归错误
    文件层级结构

    - manage.py - gunicorn_config.py - function -- handler.py -- ... -- packageA ---- api.py <- 此处调用 requests 方法 eg. get(), post() 

    gunicorn 配置

    manage.py 开头已经打了 monkey patch

    gunicorn 运行命令

    gunicorn -c gunicorn_config.py manage.py 

    错误

    版本 python3.6.9 gunicorn 20.0.4 gevent 1.4.0 docker images alpine (费了老半天才装上 gevent...)
    先谢谢各位大佬

    19 条回复    2020-03-13 16:21:29 +08:00
    Ritter
        1
    Ritter  
    OP
       2020 年 3 月 12 日
    大佬们都下班了吗 T T
    Ritter
        2
    Ritter  
    OP
       2020 年 3 月 12 日 via Android
    gunicorn -c gunicorn_config.py manage.py 写错了
    应该是 gunicorn -c gunicorn_config.py manage:app
    cz5424
        3
    cz5424  
       2020 年 3 月 12 日 via iPhone
    看不懂啥操作,猴子补丁跟你 requests 递归有什么关系?
    wuwukai007
        4
    wuwukai007  
       2020 年 3 月 12 日 via Android
    代码贴全一点
    Qzier
        5
    Qzier  
       2020 年 3 月 13 日 via iPhone
    把 flask 换成 starlette
    Ritter
        6
    Ritter  
    OP
       2020 年 3 月 13 日
    @cz5424 不打猴子补丁也会报这个错误 但是我看网上说 gunicorn 使用 gevent 内部已经 patch 了 很奇怪
    Ritter
        7
    Ritter  
    OP
       2020 年 3 月 13 日
    @wuwukai007 其他的没什么代码了就是在 api.py 文件调用了 requests 的 get,post 方法
    Ritter
        8
    Ritter  
    OP
       2020 年 3 月 13 日
    @Qzier 公司所有 Python app 都是用这个框架 这个不好换。。。
    Ritter
        9
    Ritter  
    OP
       2020 年 3 月 13 日
    github.com/gevent/gevent/issues/1531
    这个 issues 跟我情况差不多
    todd7zhang
        10
    todd7zhang  
       2020 年 3 月 13 日
    todd7zhang
        11
    todd7zhang  
       2020 年 3 月 13 日
    这里有说, 先 monkey.patch_all(), 你可以看看是不是 gunicorn_config.py 第一行的 from function.handler import app, db 这里面是不是有 import requests
    Ritter
        12
    Ritter  
    OP
       2020 年 3 月 13 日
    @todd7zhang 已经试过先在 gunicorn_config 打 patch 还是一样会报错
    ClericPy
        13
    ClericPy  
       2020 年 3 月 13 日
    呃, 提几个常识

    1. 猴子补丁要加在所有文件最顶端引用, 看你这情况 config.py 明显是在 manage.py 的顶端, 所以不该在后者打, 而是在前者那里打
    2. gunicorn 借用 gevent 提速来优化 socket io 的时候, 连 workers 也要换的, 具体操作一般是 gunicorn -k gevent, 也就是你在 config.py 里的 worker class 那个参数, 所以就像第一点说的, 这个文件顶部才需要打, 不需要在 manage 里显性再 patch all 一次.

    所以我一般 gunicorn handle flask 的时候, 是单独开一个符合 wsgi 的 py 文件, 里面产生一个 app, 而不是用 flask 自带生成的 manage.py 来操作

    PS: 实际看你的报错, 最常见于违反相互引用的问题 (昨天刚写出来一个这种错误, 虽然大部分情况下 python 做过优化来防止多次引用, 但相互依赖还是违反常识的会递归报错), 比如 A 模块里的 a 在初始化的时候依赖 B 模块的 b 的初始化, 恰恰 B 在初始化的时候又依赖了 A 里 a 的初始化, 也就产生了死锁无限递归去初始化
    Ritter
        14
    Ritter  
    OP
       2020 年 3 月 13 日
    @ClericPy 已经试过在 config 前打了还是会报错 我看了 gunicorn 内部使用 gevent 的时候也已经 patch 了 所以我觉得应该不需要打了吧 可以顺便请教一下你是怎么单独开一个符合 wsgi 的 py 文件运行 gunicorn 的吗 谢谢
    ClericPy
        15
    ClericPy  
       2020 年 3 月 13 日
    @Ritter #14 实际上就是搞一个空文件把创建 app 对象的过程单独抛出来, 网上到处都是...
    ```
    manage 因为我六七年没用 flask 命令行去初始化也不知道里面经历的什么... 看你上面图片 config 开头就引用 app 就是个典型错误, 因为补丁要打在所有操作之前, 而 config 的第一个操作不像打补丁而是 去 handler 里 import 东西, 所以这个错误不知道你后面修了没有
    ```

    我回复里点 py 居然报了一大堆 请不要在每一个回复中都包括外链,这看起来像是在 spamming

    这论坛也不能贴代码...
    ClericPy
        16
    ClericPy  
       2020 年 3 月 13 日
    在 docker 里调试如果费劲, 可以用最短案例先复现一个必定发生的代码吧, 那样举例子不会暴露源码也能更清晰地找问题...

    又重新看了下你报错, 我好像误解了, 实际错误应该是 gevent 在 3.6 上给 ssl 打补丁的那个常见错误
    Ritter
        17
    Ritter  
    OP
       2020 年 3 月 13 日
    @ClericPy docker 不打 patch 都可以 线上就 bug 我吐了
    ClericPy
        18
    ClericPy  
       2020 年 3 月 13 日
    @Ritter #17 是啊, 就是 patch 位置不对, 一定要在第一行要执行的代码里打, 用多了就习惯了, 三四年没碰过 gevent 了...
    triangle111
        19
    triangle111  
       2020 年 3 月 13 日
    import gevent.monkey
    gevent.monkey.patch_all()

    # 服务地址( adderes:port )
    bind = '127.0.0.1:5002'
    # 启动进程数量
    workers = 2
    worker_class = 'gevent'
    threads = 20
    preload_app = True
    reload = True
    x_forwarded_for_header = 'X_FORWARDED-FOR'
    chdir = './'
    proc_name='gunicorn.pid'
    #记录 PID
    pidfile='debug.log'
    access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"'
    #设置 gunicorn 访问日志格式,错误日志无法设置
    errorlog = "./errlog"
    accesslog = "./logs"

    贴一下自己
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2948 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 47ms UTC 03:07 PVG 11:07 LAX 20:07 JFK 23:07
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86