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
V2EX  ›  Python

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

  •  
  •   Ritter · 2020-03-12 17:34:10 +08:00 · 3802 次点击
    这是一个创建于 1746 天前的主题,其中的信息可能已经有所发展或是发生改变。

    环境是 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-03-12 17:53:31 +08:00
    大佬们都下班了吗 T T
    Ritter
        2
    Ritter  
    OP
       2020-03-12 18:02:15 +08:00 via Android
    gunicorn -c gunicorn_config.py manage.py 写错了
    应该是 gunicorn -c gunicorn_config.py manage:app
    cz5424
        3
    cz5424  
       2020-03-12 19:59:28 +08:00 via iPhone
    看不懂啥操作,猴子补丁跟你 requests 递归有什么关系?
    wuwukai007
        4
    wuwukai007  
       2020-03-12 20:57:32 +08:00 via Android
    代码贴全一点
    Qzier
        5
    Qzier  
       2020-03-13 02:56:33 +08:00 via iPhone
    把 flask 换成 starlette
    Ritter
        6
    Ritter  
    OP
       2020-03-13 08:53:45 +08:00
    @cz5424 不打猴子补丁也会报这个错误 但是我看网上说 gunicorn 使用 gevent 内部已经 patch 了 很奇怪
    Ritter
        7
    Ritter  
    OP
       2020-03-13 08:54:40 +08:00
    @wuwukai007 其他的没什么代码了就是在 api.py 文件调用了 requests 的 get,post 方法
    Ritter
        8
    Ritter  
    OP
       2020-03-13 08:58:51 +08:00
    @Qzier 公司所有 Python app 都是用这个框架 这个不好换。。。
    Ritter
        9
    Ritter  
    OP
       2020-03-13 09:04:30 +08:00
    github.com/gevent/gevent/issues/1531
    这个 issues 跟我情况差不多
    todd7zhang
        10
    todd7zhang  
       2020-03-13 09:07:16 +08:00
    todd7zhang
        11
    todd7zhang  
       2020-03-13 09:08:31 +08:00
    这里有说, 先 monkey.patch_all(), 你可以看看是不是 gunicorn_config.py 第一行的 from function.handler import app, db 这里面是不是有 import requests
    Ritter
        12
    Ritter  
    OP
       2020-03-13 09:22:06 +08:00
    @todd7zhang 已经试过先在 gunicorn_config 打 patch 还是一样会报错
    ClericPy
        13
    ClericPy  
       2020-03-13 09:27:17 +08:00
    呃, 提几个常识

    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-03-13 09:33:43 +08:00
    @ClericPy 已经试过在 config 前打了还是会报错 我看了 gunicorn 内部使用 gevent 的时候也已经 patch 了 所以我觉得应该不需要打了吧 可以顺便请教一下你是怎么单独开一个符合 wsgi 的 py 文件运行 gunicorn 的吗 谢谢
    ClericPy
        15
    ClericPy  
       2020-03-13 09:50:39 +08:00
    @Ritter #14 实际上就是搞一个空文件把创建 app 对象的过程单独抛出来, 网上到处都是...
    ```
    manage 因为我六七年没用 flask 命令行去初始化也不知道里面经历的什么... 看你上面图片 config 开头就引用 app 就是个典型错误, 因为补丁要打在所有操作之前, 而 config 的第一个操作不像打补丁而是 去 handler 里 import 东西, 所以这个错误不知道你后面修了没有
    ```

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

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

    又重新看了下你报错, 我好像误解了, 实际错误应该是 gevent 在 3.6 上给 ssl 打补丁的那个常见错误
    Ritter
        17
    Ritter  
    OP
       2020-03-13 11:24:42 +08:00
    @ClericPy docker 不打 patch 都可以 线上就 bug 我吐了
    ClericPy
        18
    ClericPy  
       2020-03-13 12:48:02 +08:00
    @Ritter #17 是啊, 就是 patch 位置不对, 一定要在第一行要执行的代码里打, 用多了就习惯了, 三四年没碰过 gevent 了...
    triangle111
        19
    triangle111  
       2020-03-13 16:21:29 +08:00
    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   ·   实用小工具   ·   5497 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 08:29 · PVG 16:29 · LAX 00:29 · JFK 03:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.