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

我的这个场景是不是不适合 epoll

  •  
  •   pyKun · 2014-09-11 10:48:48 +08:00 · 4355 次点击
    这是一个创建于 3718 天前的主题,其中的信息可能已经有所发展或是发生改变。
    我的场景:
    1. client 端用 python 的多线程去并发请求一个服务,其中并发度可调节5,10,50,之类的,服务本身没有负载均衡,一个进程(一个worker)单纯的处理,也就是说,场景是简单的 n 个并发到一个端口上的服务

    2. 服务端业务处理简单,基本就是在 mysql 中插入一条记录(其实是认证用的 token)
    3. server 端用的是 python 和 eventlet,eventlet 默认用的 epoll

    问题:
    我把并发调成1的时候,效率大概是每个请求都能在0.2秒完成
    但,当我把并发调成5左右的时候,有的请求会被 delay 很久,我自己的统计大概是:
    1. 0.2s
    2. 0.2s
    3. 15s
    4. 0.2s
    ...

    总有那么几个倒霉的线程,在请求 server 的时候总会被忽略,然后就出现了上面 3 的那个情况,完成时间是别的线程的几十倍

    另一个现象是,顺序的请求的话,比如 100 个请求用了 25s 的时间,那 100 个并发的请求会在35s 左右,也就是 server 段出现了 overhead

    我自己的想法:
    1. 首先单 worker 是根源,25s 的总请求时间变成 35s,是因为 epoll 在上下文切换的时候造成的,而且业务本身的性质并没有多少空闲(epoll之类的选举算法是当一个请求空闲的时候,切换下,让别人跑跑),也就是没有多少收益。收益 < 上下文切换带来的代价,所以总相应时间会变多

    2. 上面例子中的 3 无法理解,为什么总有一个请求者(线程)总是没法被 epoll 选到呢?不能只是运气差吧
    13 条回复    2014-09-12 09:12:20 +08:00
    reusFork
        1
    reusFork  
       2014-09-11 11:03:45 +08:00   ❤️ 1
    epoll是用来通知io事件的,和线程无关,和上下文切换也无关。线程的上下文切换也不会产生10秒的差别。epoll不是选举算法,等待io时切换,那是协程负责的工作。
    没有具体的代码,没人可以帮你定位bug。
    pyKun
        2
    pyKun  
    OP
       2014-09-11 12:14:24 +08:00
    @reusFork

    怀疑到 epoll 是因为,用 python 的 trace 模块追踪 server 这块的时候,发现消耗时间最多的是:

    .... 56.894 .... {method 'poll' of 'select.epoll' objects}

    56秒那个是这段测试时间,跑 select.epoll.poll 这里总的消耗时间(平均的 * 次数)

    在并发5,请求 100 次的时候 epoll.poll 一共消耗了 56 秒

    但是顺序请求 100 次的时候,这里只有 3 秒多(另外一个不同时,这个方法被 call 的次数在鬓发的时候 2w 到 4w 不等,顺序的时候,只有 1w;平均消耗时间,并发的时候是 0.03s,顺序的时候 0.00s 就是小于 0.005s)
    (上文的 25s ~ 35s 只是举例子)

    另外,select 模块的位置是 /usr/lib64/python2.6/lib-dynload/selectmodule.so

    rpm -qf 这个文件发现这个位置的文件是来自于 python-libs 这个包

    以上均是客观事实了,能帮我小分析下么 :)
    pyKun
        3
    pyKun  
    OP
       2014-09-11 12:17:44 +08:00
    @reusFork

    另外,用 python 的 trace 模块统计的时候,除了 select.epoll.poll 这个地方,其他函数的总时间统计在并发和顺序的情况下没有多大差别
    nybux
        4
    nybux  
       2014-09-11 12:30:35 +08:00   ❤️ 1
    适合epoll,但是不适合你这样做,mysql调用要调度到一个线程池里面。或者你用pymysql+gevent,把mysql的netio也异步化
    pyKun
        5
    pyKun  
    OP
       2014-09-11 12:48:29 +08:00
    @nybux

    > mysql调用要调度到一个线程池里面

    这句话的意思我的请假下既然没有 fork 出来的多进程(worker)了,那直接让访问的mysql的线程池化,从而加速处理?
    mucid
        6
    mucid  
       2014-09-11 13:18:40 +08:00
    mysql得用异步驱动才行
    dafang
        7
    dafang  
       2014-09-11 13:24:26 +08:00
    连接MySQL的地方,改用nonblocking的库...
    nybux
        8
    nybux  
       2014-09-11 14:31:42 +08:00
    你现在的瓶颈在于mysql请求,虽然通过eventlet可以在单线程中并发处理大量请求,但是因为整个程序是单线程的。所以,所有的mysql处理最终还是会排队执行。整个程序的吞吐量就是取决于你的单线程执行mysql的效率。所以把mysql请求放到线程池中,就能缓解状况。
    leyle
        9
    leyle  
       2014-09-11 18:44:49 +08:00 via Android
    100次顺序请求都要耗时25秒,首先需要解决的是单次请求的耗时吧,服务端从接到请求到处理完毕,单次千分之一秒的耗时我觉得还算能接受
    leyle
        10
    leyle  
       2014-09-11 18:47:45 +08:00 via Android
    并且你对 epoll 的理解是错的,如果想深入正经的理解几种无阻塞 I/O 模型,可以参考 the linux programming interface 64章的内容
    pyKun
        11
    pyKun  
    OP
       2014-09-11 19:54:28 +08:00
    @leyle
    100次请求是实际的,25s和35s是在主贴里大概描述的,顺序的情况下都0.02s左右完成,再优化是之后的任务了,不过千分之一秒这个目标不错,自己之前没啥概念

    我遇到的问题还是如之前所说,并发的时候(哪怕并发只有5)会出现诡异情况:
    1. 0.2s
    2. 0.2s
    3. 15s
    4. 0.2s
    ...

    python的trace结果是select.epoll.poll总耗时太长(顺序的总耗时3s左右,5并发100总请求的情况都有50s了)

    正在用大家意见调整mysql到nonblocking再测
    mengskysama
        12
    mengskysama  
       2014-09-12 09:09:04 +08:00
    你这个业务流程就是顺序执行嘛,为啥会用epool。worker模式不用epool,参照php cgi。
    异步数据库处理时间不会比现在少,空转和异步cb的时间应该是相当的。
    先查查是不是数据库是不是有锁表,还有数据库是不是有连接数或者性能上限制。
    pyKun
        13
    pyKun  
    OP
       2014-09-12 09:12:20 +08:00
    @mengskysama

    eventlet 默认是 epoll,当然这个我可以改,但是

    1. 0.2s
    2. 0.2s
    3. 15s
    4. 0.2s

    这个现象里面的3,就不理解了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2607 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 15:40 · PVG 23:40 · LAX 07:40 · JFK 10:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.