怎样异步执行 gevent.spawn(),避免主进程阻塞? - 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
tomzhu

怎样异步执行 gevent.spawn(),避免主进程阻塞?

  •  
  •   tomzhu 2016 年 10 月 20 日 12412 次点击
    这是一个创建于 3474 天前的主题,其中的信息可能已经有所发展或是发生改变。

    一直在用 multiprocessing 和 threading ,遇到内存、资源消耗等问题,想要用gevent.spawn()改写。

    我的主进程是一个 rpc 服务器(不能被阻塞),我只想要异步执行一段代码,不想要结果(代码片段会调用 client 通知结果给主进程), 如果用join 会阻塞。

    看了一篇文章 http://www.jianshu.com/p/571db0eb95f8 作者说道:

    我在 Python shell 中 gevent.spawn 一个函数,它怎么不运行? 按照自然的思维就是 spawn 后就应该要运行啊。 Erlang 就是这样的

    为什么 spawn 出的协程要 join ,一调用 join 就会把整个 python process 阻塞住。丝毫感觉不到异步啊。

    在学习两次失败后,后来终于想明白了:

    shell 中 spawn 不运行,是因为 gevent 的 event loop 没有跑起来,无法去调度 greenlet 。

    join 就是在启动 gevent 的 gevent loop ,一旦 gevent loop 通过其他方式启动起来了, 那么就可以在程序中自然的 spawn 进程。新 spawn 的 greenlet 会被调度执行。

    当跨过这个障碍后,学习和使用 Gevent 容易了很多。

    很想知道怎样启动 gevent loop ,可以让我新的 spawn 自动异步运行? 尝试了以下代码

    gevent.spawn(task) gevent.sleep(0) 

    可以跑通,但是 task 函数内如果有 gevent.sleep(2), grequest 之类的语句,就会出现跑一半不跑了的情况,觉得不靠谱会这样那样的意外,因为我没有办法干涉 task 函数。

    这让我感觉到 gevent 在 python 大型应用程序的使用率应该很低,要么全部都用,要么全部都不能用,大部分团队多半会选择后者。

    想的有点多了,不知道是不是这样呢

    17 条回复    2016-10-24 15:41:55 +08:00
    R4rvZ6agNVWr56V0
        1
    R4rvZ6agNVWr56V0  
       2016 年 10 月 20 日
    “是因为 gevent 的 event loop 没有跑起来,无法去调度 greenlet ” 你确定是这个原因? spawn 一个函数,函数里内容是啥?
    tomzhu
        2
    tomzhu  
    OP
       2016 年 10 月 20 日
    @GeekGao 所以我必须要知道函数的内容才能用 gevent.spawn 吗? FYI, 函数内容是调用 client 给 rpc 服务器发送请求并获取返回,这个请求可能瞬间也可能需要数秒,取决于服务器怎么处理。
    yufpga
        3
    yufpga  
       2016 年 10 月 20 日
    先找到程序中被阻塞部分, 改为非阻塞的.
    tomzhu
        4
    tomzhu  
    OP
       2016 年 10 月 20 日
    @yufpga 问:怎么改?答:用 gevent.spawn 。"又回到最初的起点,呆呆的站在镜子前,笨拙#~*&(@$!#$^@#%!~"
    neoblackcap
        5
    neoblackcap  
       2016 年 10 月 20 日
    @tomzhu 你需要了解 Linux 编程里面的 IO 操作, gevent.spawn 只是一个封装,你大可用系统调用 ioctl 将 fd 设成非堵塞,那么所有的读都是非堵塞的了
    yufpga
        6
    yufpga  
       2016 年 10 月 20 日
    我不知道你的程序阻塞在哪了, 建议先看一下 gevent 的猴子补丁部分的内容(会让你对这个问题出现的原因有个大概的认知), 如果猴子补丁并不能解决你阻塞的问题, 建议还是换一个方案.当然, 阻塞变非阻塞不是 gevent.spawn 干的事.
    R4rvZ6agNVWr56V0
        7
    R4rvZ6agNVWr56V0  
       2016 年 10 月 20 日
    @tomzhu 一次 spawn 看不出啥的
    fds
        8
    fds  
       2016 年 10 月 20 日
    好几年没用了。不过我印象中 gevent 是协作式的并行,同一时刻只能有一个协程运行,必须由它主动让出自己的执行状态,换成别的协程。
    所以如果某一协程要做网络调用,那么应该在发起非阻塞请求,然后让出执行权,等待别人再把执行权交给回自己。
    一般都是通过 monkey patch ,把 python 的一些库函数包装成使用 gevent 的。但有些没包装的,就可能会阻塞了,要自己改。
    binux
        9
    binux  
       2016 年 10 月 20 日
    你是不是理解错了什么, gevent 并不能让你的程序「异步」运行,它只能帮你在 event wait 时切换协程罢了。
    例如你的 task 是计算型的,没有 event wait 或者主线程不将执行权限交还给 gevent (例如 gevent.sleep ),它怎么切换?怎么去执行其他的协程?
    binux
        10
    binux  
       2016 年 10 月 20 日
    所以,该用进程或者线程的时候就要用啊。
    neoblackcap
        11
    neoblackcap  
       2016 年 10 月 20 日
    @binux 我觉得,还是先推荐读 UNP 比什么都重要,读后才开始“异步”编程,否则一个 sleep ,或者 gevent 里面写日志到本地文件,就全线爆炸了。
    太多新人根本不了解所谓的异步,同步,堵塞,非堵塞然后就开始上各种框架,这是一切的问题的根源啊。
    tomzhu
        12
    tomzhu  
    OP
       2016 年 10 月 20 日
    看了这么多回复,原来 gevent 并不能让我异步化,我还是继续用 threading 吧,谢谢大家!
    tomzhu
        13
    tomzhu  
    OP
       2016 年 10 月 20 日
    @yufpga 我的程序阻塞在 task 函数里面。猴子补丁会让我的应用程序充满不确定性,除非我很清楚他究竟 monkeypatch 了哪些模块,否则我不会用的
    tomzhu
        14
    tomzhu  
    OP
       2016 年 10 月 20 日
    @binux 嗯我想我在那个地方应该用的是线程,谢谢你对 gevent ,和切换协程的解释
    neoblackcap
        15
    neoblackcap  
       2016 年 10 月 20 日
    @tomzhu 不用 monkeypatch.patch_all(),你可以自己一个一个 patch ,具体 patch 了什么 https://github.com/gevent/gevent/blob/master/src/gevent/monkey.py#L575
    两大切记, gevent 在面对 CPU 密集型以及本地 IO 密集型的任务,都很无力
    sleshep
        16
    sleshep  
       2016 年 10 月 22 日
    @binux
    我怀疑他的 patch_all 不在第一行。。。。
    tomzhu
        17
    tomzhu  
    OP
       2016 年 10 月 24 日
    @sleshep 请先看懂我的问题谢谢!
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2875 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 42ms UTC 03:13 PVG 11:13 LAX 20:13 JFK 23:13
    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