Python 多线程问题 - 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
latteczy
V2EX    Python

Python 多线程问题

  •  1
     
  •   latteczy 2015-07-07 20:20:58 +08:00 4635 次点击
    这是一个创建于 3760 天前的主题,其中的信息可能已经有所发展或是发生改变。


    上面的代码分别用多线程和普通方式抓取页面信息。但是二者运行时间相差无几,大约都是0.7+秒。这里应该不是CPU密集型,所以多线程应该有效率的提高才对。不知是何原因?
    最近在学习Python的多线程,请大神多多指教!
    28 条回复    2015-07-13 08:30:29 +08:00
    realityone
        1
    realityone  
       2015-07-07 20:28:15 +08:00
    你在 q 里面再加一句 time.sleep(5) 然后观察下就知道问题在哪里了



    `t.join()`
    RichardZhiming
        2
    RichardZhiming  
       2015-07-07 20:32:02 +08:00 via Android
    尽量使用多进程,gil是Python的历史遗留问题
    latteczy
        3
    latteczy  
    OP
       2015-07-07 20:36:14 +08:00
    @RichardZhiming 嗯,只是想搞明白这个Python的多线程是怎么回事
    zhyu
        4
    zhyu  
       2015-07-07 20:36:55 +08:00
    join([timeout])
    Wait until the thread terminates. This blocks the calling thread until the thread whose join() method is called terminates either normally or through an unhandled exception or until the optional timeout occurs.
    latteczy
        5
    latteczy  
    OP
       2015-07-07 20:40:32 +08:00
    @realityone 加上time.sleep(5)之后结果是21秒多,还是不太明白,麻烦能否再指点一下。是t.join()有问题么?
    latteczy
        6
    latteczy  
    OP
       2015-07-07 20:43:09 +08:00
    @zhyu 额,join()是要等待该线程结束才能再起其他的线程啊。也就是说加上join()就跟单线程一样咯?
    Shazoo
        7
    Shazoo  
       2015-07-07 20:43:33 +08:00
    threads = []
    for i in range(4):
    t = threading.Thread(target=q, args=(hosts[i],))
    threads.append(t)
    t.start()

    for t in threads:
    t.join()

    这样应该会快些。
    alexapollo
        9
    alexapollo  
       2015-07-07 20:56:35 +08:00
    建议你用多进程 multiprocessing 模块。
    python 的线程机制比较弱,一般用多进程或异步解决这个问题。
    latteczy
        10
    latteczy  
    OP
       2015-07-07 21:02:54 +08:00
    @alexapollo 我知道,我只是想弄明白Python的多线程是怎么回事。而且对于这段代码,多线程应该是会有效率上的提高的,但是我并没测试出有提高。所以想弄明白是怎么回事。
    alexapollo
        11
    alexapollo  
       2015-07-07 21:08:03 +08:00
    @latteczy GIL,查了就懂了。活用google,SO上这种问题蛮多的
    latteczy
        12
    latteczy  
    OP
       2015-07-07 21:19:50 +08:00
    @alexapollo 嗯,这段代码效率没提高就是楼上所说的t.join()位置不对。主要原因不在GIL吧
    alexapollo
        13
    alexapollo  
       2015-07-07 21:22:53 +08:00
    @latteczy 恩,是的
    est
        14
    est  
       2015-07-07 21:27:07 +08:00
    GIL 真是个活靶子。
    latteczy
        15
    latteczy  
    OP
       2015-07-07 21:39:25 +08:00
    @Shazoo 感谢!确实是这样。但是又有个问题是代码改正以后貌似没法统计运行时间了。。
    https://gist.github.com/smartczy/35e692064b775dcc3e17#comment-1487649
    uniquecolesmith
        16
    uniquecolesmith  
       2015-07-07 21:44:00 +08:00
    gevent 用起来
    aec4d
        17
    aec4d  
       2015-07-07 22:06:43 +08:00
    这TM关GIL毛事 简直躺枪
    要记住 断然给你提GIL的 要么是高手 要么是SB 有GIL还有multiprocessing呢 多线程最需要注意的应该是线程安全
    这是threading.join的文档
    join([timeout])
    Wait until the thread terminates. This blocks the calling thread until the thread whose join() method is called terminates either normally or through an unhandled exception or until the optional timeout occurs.

    When the timeout argument is present and not None, it should be a floating point number specifying a timeout for the operation in seconds (or fractions thereof). As join() always returns None, you must call isAlive() after join() to decide whether a timeout happened if the thread is still alive, the join() call timed out.

    When the timeout argument is not present or None, the operation will block until the thread terminates.

    A thread can be join()ed many times.

    join() raises a RuntimeError if an attempt is made to join the current thread as that would cause a deadlock. It is also an error to join() a thread before it has been started and attempts to do so raises the same exception.

    看了之后你就发现 在上面加上t.join就和下面遍历的写法实质上是一模一样的.
    一般网上很多教程给你加上setDaemon 加上join 你可以试着不加看是什么样的。等你熟悉了之后你就晓得那时候该用这些 哪时候不该用
    zhyu
        18
    zhyu  
       2015-07-07 22:59:29 +08:00 via iPhone
    @latteczy
    试试不要join
    latteczy
        19
    latteczy  
    OP
       2015-07-08 08:27:41 +08:00
    @aec4d 多谢大神指点!大神莫激动。。。
    fanta
        20
    fanta  
       2015-07-08 09:32:06 +08:00
    aec4d 说的对,每个连接是0.7s时,问题已不是多线程的问题了, 是网络(服务器链路)问题.
    Shazoo
        21
    Shazoo  
       2015-07-08 10:08:30 +08:00
    @latteczy

    如果需要统计时间,我觉得你可以在线程内部实现的。退出前打印下即可。如果要保证和之前类似的输出,就需要考虑在主线程内阻塞等待了。
    latteczy
        22
    latteczy  
    OP
       2015-07-08 14:41:34 +08:00
    @Shazoo 也就是说,保证按之前的请求顺序输出和提高效率二者始终是矛盾的,这么理解对吧?
    yuyang
        23
    yuyang  
       2015-07-08 14:54:33 +08:00
    @aec4d 网上一票SB只要看到别人用python写多线程程序,立马就喷,立马搬出GIL,立马要你改成多进程,以前我还会吐槽下这些不懂装懂的家伙,现在直接无视..
    sampeng
        24
    sampeng  
       2015-07-08 16:43:55 +08:00
    不是所有的多线程一定带来效益的提升。。。。。尤其是里面有网络请求这样的东西的时候。
    线程同步会坑很大一堆时间,完全和多线程带来的收益抵消甚至更严重的问题。

    个人看法,多线程只用在相互之间毫无关系,一丁点关系都没有。不需要同步状态。没有顺序关联的时候是最有效的。其他时候,纯粹是自己给自己找麻烦(线程同步很蛋疼的)
    ryd994
        25
    ryd994  
       2015-07-08 17:56:00 +08:00 via Android
    @sampeng 这种情况还好吧……加锁就可以了
    latteczy
        26
    latteczy  
    OP
       2015-07-10 08:35:11 +08:00
    @Shazoo
    这个地方不加join和加
    for t in threads:
    t.join()
    效果应该是一样的吧
    qqblog
        27
    qqblog  
       2015-07-11 14:26:33 +08:00
    计划今后生产、开发环境换成pypy,版本未定
    Shazoo
        28
    Shazoo  
       2015-07-13 08:30:29 +08:00
    @latteczy 也不矛盾了。你如果需要得到类似顺序执行的结果,就需要线程之间同步。同步方法有很多,这个情况下,比较简单的就是每个线程都记录下自己的执行时间,然后所有线程结束后,比较下,输出最长即可。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5201 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 40ms UTC 07:30 PVG 15:30 LAX 00:30 JFK 03:30
    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