论坛首页 编程语言技术论坛

2.7相比2.4的多线程性能提高了..

浏览 13133 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (2)
作者 正文
   发表时间:2012-03-02   最后修改:2012-03-02
一开始在2.4下用线程做,发现不给力,一看2.7有 multiprocessing,就升上去了,用multiprocessing,发现挺快,告诉自己GIL果然冥冥之中主宰了python的多线程能力...
昨天在2.7下换回多线程,发现一样的性能...

multiprocessing岂不意义不大了?不过我觉得可能是我在进程间共用了一个Queue所致,如果进程间不通信,会不会好点?
   发表时间:2012-03-02  
我错了,我自问自答..忽然发觉另一个处理日志的程序,用进程比线程快了近一倍。

差不多可以确定,资源争用影响性能。
0 请登录后投票
   发表时间:2012-03-02  
操作系统对于进程的调度,比线程库对于线程的调度,要可靠、准确得多。
0 请登录后投票
   发表时间:2012-03-11  
应该不是说windows吧
0 请登录后投票
   发表时间:2012-03-12  
multiprocessing 在windows下相当慢。和os的机制有关。

在*nix下相当快,基本上可以替代thread
0 请登录后投票
   发表时间:2012-03-13  
我记得是这样的:
Python中多线程一定是按照时间片划分的方式工作,因为它有个全局锁(叫什么我忘了),这个锁在任何时候都只能有一个线程获得。这意味着即使你有多核CPU,使用多线程方式你的程序也利用不了100%的CPU。
多线程方式:
import threading

def forevery() :
    while True:
        pass

t1 = threading.Thread(target=forevery)
t1.setDaemon(True)
t1.start()

forevery()

print 'go on...'

我的机器是Ubuntu 双核。CPU撑不满。
但换成多进程方式就可以:
import multiprocessing

def forevery() :
    while True:
        pass

p1 = multiprocessing.Process(target=forevery)
p1.start()

forevery()

print 'go on...'

这个程序可以沾满两个CPU
---------------------------------------
这说明至少在linux平台上,python的多进程方式比多线程方式更能利用CPU多核优势。

那剩下的就是看你的应用类型了,如果你的应用是个CPU bunding类型,而不是IO bunding类型,那么多进程比较适合。反或来,如果你的应用的是IO bunding类型,例如Web服务等等,那么多进程可能就没什么优势了,反正阻塞在IO上面,CPU再多也没用,那还不如换多线程,对操作系统来说也更轻量级一些。

仅个人认识,不要轻信
0 请登录后投票
   发表时间:2012-03-13   最后修改:2012-03-13
感谢各位回复,是SUSE Linux上的,是一个Socket Server,收消息,发响应,存消息,然后再构造请求发回去。

这几天在做另一个桩,处理一个很偏门的协议,叫UCP,处理协议细节很麻烦。其中一个细节是,往对端发的请求是非阻塞式的,可以一股脑儿拽过去N多请求,响应你对端可以慢慢回,但是有个限制:最多可以允许有100条请求没有收到响应。所以在发送请求时有下面这段:
      if msgQueue.qsize()>0 and noResReportCount<100:
         print msgQueue.qsize()
         buffer=msgQueue.get().split(':')
         theSocket.sendall(encodeReport(buffer)) //发送请求给对端

         noResReportCount+=1


但是忽然发现,这段代码在一个线程的target函数里,会有并发问题:如果有10个线程同时判断进入条件为真,都进去了,那么最后noResReportCount会涨到109,破坏了“100条规则”...

不想加锁,于是改成了:

      if msgQueue.qsize()>0 and noResReportCount<100:
         noResReportCount+=1
         #in order that concurrent access
         if noResReportCount>100:
            noResReportCount-=1
            break      //外面有while循环,如果破坏了100条规则就直接退出
         print msgQueue.qsize()
         buffer=msgQueue.get().split(':')
         theSocket.sendall(encodeReport(buffer))
线程这个东西没经验不能用啊,开发们估计这方面积累较多吧,测试伤不起...

0 请登录后投票
   发表时间:2012-03-14   最后修改:2012-03-14
      
         if msgQueue.qsize()>0 and noResReportCount<100:
         noResReportCount+=1
         #in order that concurrent access
         if noResReportCount>100:
            noResReportCount-=1
            break      //外面有while循环,如果破坏了100条规则就直接退出
         print msgQueue.qsize()
         buffer=msgQueue.get().split(':')
         theSocket.sendall(encodeReport(buffer))


恐怕还是不行,假设当前noResReportCount = 90,10条线程都到执行 noResReportCount+=1的位置,10条轮换这执行noResReportCount+=1,结果 noResReportCount = 100,再往下进行一起轮换执行 if noResReportCount>100,结果都会命中,再往下去轮换执行noResReportCount-=1,减到90(这时已经晚了),最后一起退出。也就是说有可能达不到原来要求的最大限。100 - 线程数 = 你的消息条数,如果的线程数很大,就有可能一条都发不出去。
0 请登录后投票
   发表时间:2012-03-14  
一定要用多线程、多进程吗?看看Twisted(对应于Ruby:EventMachine,JavaScript:Node.js)。
0 请登录后投票
   发表时间:2012-03-15  
shenyu 写道
      
         if msgQueue.qsize()>0 and noResReportCount<100:
         noResReportCount+=1
         #in order that concurrent access
         if noResReportCount>100:
            noResReportCount-=1
            break      //外面有while循环,如果破坏了100条规则就直接退出
         print msgQueue.qsize()
         buffer=msgQueue.get().split(':')
         theSocket.sendall(encodeReport(buffer))


恐怕还是不行,假设当前noResReportCount = 90,10条线程都到执行 noResReportCount+=1的位置,10条轮换这执行noResReportCount+=1,结果 noResReportCount = 100,再往下进行一起轮换执行 if noResReportCount>100,结果都会命中,再往下去轮换执行noResReportCount-=1,减到90(这时已经晚了),最后一起退出。也就是说有可能达不到原来要求的最大限。100 - 线程数 = 你的消息条数,如果的线程数很大,就有可能一条都发不出去。

也是啊
是不是只有用锁把
        if noResReportCount>100:
            noResReportCount-=1
            break  

锁住了?
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics