V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
推荐学习书目
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
hihihihihi
V2EX  ›  Python

gevent 代码是运行在一个线程里面吗?

  •  
  •   hihihihihi · Aug 31, 2016 · 3689 views
    This topic created in 3526 days ago, the information mentioned may be changed or developed.
    python 初学者, 偶然看到网上讨论 gevent ,于是把我之前的 thread 修改成了 gevent 的,

    但是我在调试的时候,发现 call stack 里面在调用那部分 gevent 代码的时候,新建了 10 来个新的线程

    不是说 gevent 都运行在一个线程里面吗?

    大致的伪代码如下:

    以前用多线程来做,
    1000 tasks, 分成 10 个线程,每个线程分 100 个 task ,等待所有线程退出


    现在的逻辑,一个 for 循环把所有的 tasks 分给 1000 个 gevent.spawn 调用, joinall 等待退出。


    问题 1 :是不是这里 for 循环 扔 1000 个 gevent.spawn 操作太暴力了?

    问题 2 :为什么后面换成 gevent 后,居然给我创建了 10 来个线程?
    11 replies    2016-09-01 15:07:32 +08:00
    feisuzhu
        1
    feisuzhu  
       Aug 31, 2016   ❤️ 1
    1. 不暴力,这样挺好(对你的程序来讲),不会有什么压力。被请求的资源可能就蛋疼了。可以的话还是用 gevent.pool.Pool 吧,就是把 gevent.spawn 改成 pool.spawn ,剩下的活 gevent 都帮你干了。

    2. 没明白。如果只是 gevent.spawn 的话,是不会有新线程的(除非底层的代码用了,而且你也没 monkey patch )。
    你说的是每个 task 都有自己的调用栈吧?这个是正常的。
    neoblackcap
        2
    neoblackcap  
       Sep 1, 2016
    gevent 是里面是用的是协程,即用户态线程,若是指内核态线程的话那么就是一个,但用户态线程就不止一个,可能有成千上万个
    SlipStupig
        3
    SlipStupig  
       Sep 1, 2016   ❤️ 1
    gevent 分两部分: 1.greenlet 2.libev
    1.greenlet ,原理是基于 stack 的,调度的方式是基于 coroutine 主动切换,说白了就是函数之间切换
    2.libev 这个主要涉及 IO 相关的,里面用的是线程池管理,这里面不是 coroutine ,所以只要你不做 IO 相关的操作不会是多线程的
    hihihihihi
        4
    hihihihihi  
    OP
       Sep 1, 2016
    @feisuzhu

    协程函数代码里面是做了 IO 处理, urlopen 访问了网络, 刚才又测试了好多次, 这样一次性丢很多进去,程序内部可能会建立很多连接, timeout 出错概率变大,服务端也可能 drop 一些我的连接。

    而以前自己用线程来调度处理,服务器那边应该会觉得我友好一点?

    也许是我 gevent 还使用得不大对。
    hihihihihi
        5
    hihihihihi  
    OP
       Sep 1, 2016
    @SlipStupig

    是的,我做了 IO 操作, 调用 urlopen 访问了网络。而且,一次性这样弄 1000 个 urlopen ,实测 timeout 概率增多,出错几率增大,是不是我这样用 gevent 是不对的。因为网络带宽和连接数始终是有限的。 比如如果我写的服务器,可能发现一次这么多并发连接,我可能会 drop 或者 block 掉一些。
    Zzzzzzzzz
        6
    Zzzzzzzzz  
       Sep 1, 2016
    确实有线程, gevent 1.0 之后没设置环境变量 GEVENT_RESOLVER 为 ares 的话, 默认 DNS 查询一类操作走的是 gevent 自己封装的原生线程池的实现.
    SlipStupig
        7
    SlipStupig  
       Sep 1, 2016
    @4ever911 这个不是别的,对方网站不一定扛得住,或者限制了.....
    petelin
        8
    petelin  
       Sep 1, 2016
    超时的问题跟 gevent 没关系,你出口流量和对方入口流量限制,可能你以前的 10 个线程访问速度没有 gevent 来的快(很有可能),
    第二个我没看懂,感觉你的结果不对吧,话说你是怎么看出来线程数量的???
    hihihihihi
        9
    hihihihihi  
    OP
       Sep 1, 2016
    @petelin Cannot type Chinese here on this device.

    I use VS Code as my Python IDE. Through the Debug Window, I see couple threads are created right after the gevent calls.

    I have tested both codes ( threads/gevent ) for many times. It seams that gevent runs a little bit faster. But, I guess the problem is not all about CPU, maybe I need pay more attention on the network connections.
    petelin
        10
    petelin  
       Sep 1, 2016 via Android
    @4ever911 好吧,确实很神奇,期待大神来瞅瞅
    zhuangzhuang1988
        11
    zhuangzhuang1988  
       Sep 1, 2016
    上代码..
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1829 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 53ms · UTC 16:22 · PVG 00:22 · LAX 09:22 · JFK 12:22
    ♥ Do have faith in what you're doing.