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

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

  •  
  •   4ever911 · 2016-08-31 22:59:33 +08:00 · 3065 次点击
    这是一个创建于 3005 天前的主题,其中的信息可能已经有所发展或是发生改变。
    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 条回复    2016-09-01 15:07:32 +08:00
    feisuzhu
        1
    feisuzhu  
       2016-08-31 23:23:58 +08:00   ❤️ 1
    1. 不暴力,这样挺好(对你的程序来讲),不会有什么压力。被请求的资源可能就蛋疼了。可以的话还是用 gevent.pool.Pool 吧,就是把 gevent.spawn 改成 pool.spawn ,剩下的活 gevent 都帮你干了。

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

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

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

    也许是我 gevent 还使用得不大对。
    4ever911
        5
    4ever911  
    OP
       2016-09-01 09:35:33 +08:00
    @SlipStupig

    是的,我做了 IO 操作, 调用 urlopen 访问了网络。而且,一次性这样弄 1000 个 urlopen ,实测 timeout 概率增多,出错几率增大,是不是我这样用 gevent 是不对的。因为网络带宽和连接数始终是有限的。 比如如果我写的服务器,可能发现一次这么多并发连接,我可能会 drop 或者 block 掉一些。
    Zzzzzzzzz
        6
    Zzzzzzzzz  
       2016-09-01 10:14:16 +08:00
    确实有线程, gevent 1.0 之后没设置环境变量 GEVENT_RESOLVER 为 ares 的话, 默认 DNS 查询一类操作走的是 gevent 自己封装的原生线程池的实现.
    SlipStupig
        7
    SlipStupig  
       2016-09-01 10:15:30 +08:00
    @4ever911 这个不是别的,对方网站不一定扛得住,或者限制了.....
    petelin
        8
    petelin  
       2016-09-01 10:41:24 +08:00
    超时的问题跟 gevent 没关系,你出口流量和对方入口流量限制,可能你以前的 10 个线程访问速度没有 gevent 来的快(很有可能),
    第二个我没看懂,感觉你的结果不对吧,话说你是怎么看出来线程数量的???
    4ever911
        9
    4ever911  
    OP
       2016-09-01 11:25:07 +08:00
    @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  
       2016-09-01 13:09:57 +08:00 via Android
    @4ever911 好吧,确实很神奇,期待大神来瞅瞅
    zhuangzhuang1988
        11
    zhuangzhuang1988  
       2016-09-01 15:07:32 +08:00
    上代码..
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2773 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 14:45 · PVG 22:45 · LAX 06:45 · JFK 09:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.