Twisted提供的利用多核CPU的假象
Twisted中提供了一个线程延迟调用模型。Twisted本身是一个事件模型,调用一件事情以后可以延迟处理和回调,但是这些基于事件的处理实际上是在一个线程里面执行的,或者说事件循环reactor.run()实际上就是运行在主线程里面的。而线程延迟调用模型则可以在启动一个线程之后使用延迟回调功能。这是一个单线程和多线程的区别。
最近在开发一个程序的时候,需要使用这个线程延迟调用功能来查询数据库,实际上使用的函数是twisted.internet.threads.deferToThread。具体使用方法参考手册中的解释。
在使用这种编程方式之后,在一台双双核CPU的服务器上(4个CPU核),运行的时候,CPU使用率一度达到140%。令我高兴了半天,以为使用这种方式可以达到利用多核CPU的目的呢。
后来,又专门写了一个脚本用来测试这种计算的效果。结果就令我失望了,在同一时间只有一个CPU核处于工作状态,但是这个在GIL监控下的线程并不是总是运行在同一个CPU核上,所以在线程总一个核切换到另外一个核的短暂时间里就会出现同时使用2个CPU核的假象,这个时候就会显示CPU使用率超过100%了。当然,都是猜测,如果读者有高论希望不吝赐教。使用Python进行SMP编程已经郁闷我好久了。
测试并行计算的脚本如下:
"""
使用Twisted的defer线程进行并行计算的例子,查看Python能否通过这种方式利用多核CPU
"""
import time
import thread
from twisted.internet import reactor,protocol
from twisted.python import log
from twisted.internet.threads import deferToThread
all_timelong=[]
all_timelong_lock=thread.allocate_lock()
def calc(max):
"""一个自加计算,无法实现并行计算优化的,避免Python解释器对其进行优化"""
start=time.time()
result=1
for i in range(2,max+1):
result+=i
return result,(time.time()-start)
def callback(infopack):
"""回调函数"""
timelong=infopack[1]
try:
all_timelong_lock.acquire()
all_timelong.append(timelong)
print "TIME LONG: %.04f"%timelong
finally:
all_timelong_lock.release()
return
def main(threadcount):
"""起多多线程执行计算"""
for i in range(0,threadcount):
d=deferToThread(calc,2000000)
d.addCallback(callback)
#reactor.callLater(60,reactor.stop)
reactor.run()
if __name__=="__main__":
main(4)
Twisted中提供了一个线程延迟调用模型。Twisted本身是一个事件模型,调用一件事情以后可以延迟处理和回调,但是这些基于事件的处理实际上是在一个线程里面执行的,或者说事件循环reactor.run()实际上就是运行在主线程里面的。而线程延迟调用模型则可以在启动一个线程之后使用延迟回调功能。这是一个单线程和多线程的区别。
最近在开发一个程序的时候,需要使用这个线程延迟调用功能来查询数据库,实际上使用的函数是twisted.internet.threads.deferToThread。具体使用方法参考手册中的解释。
在使用这种编程方式之后,在一台双双核CPU的服务器上(4个CPU核),运行的时候,CPU使用率一度达到140%。令我高兴了半天,以为使用这种方式可以达到利用多核CPU的目的呢。
后来,又专门写了一个脚本用来测试这种计算的效果。结果就令我失望了,在同一时间只有一个CPU核处于工作状态,但是这个在GIL监控下的线程并不是总是运行在同一个CPU核上,所以在线程总一个核切换到另外一个核的短暂时间里就会出现同时使用2个CPU核的假象,这个时候就会显示CPU使用率超过100%了。当然,都是猜测,如果读者有高论希望不吝赐教。使用Python进行SMP编程已经郁闷我好久了。
测试并行计算的脚本如下:
"""
使用Twisted的defer线程进行并行计算的例子,查看Python能否通过这种方式利用多核CPU
"""
import time
import thread
from twisted.internet import reactor,protocol
from twisted.python import log
from twisted.internet.threads import deferToThread
all_timelong=[]
all_timelong_lock=thread.allocate_lock()
def calc(max):
"""一个自加计算,无法实现并行计算优化的,避免Python解释器对其进行优化"""
start=time.time()
result=1
for i in range(2,max+1):
result+=i
return result,(time.time()-start)
def callback(infopack):
"""回调函数"""
timelong=infopack[1]
try:
all_timelong_lock.acquire()
all_timelong.append(timelong)
print "TIME LONG: %.04f"%timelong
finally:
all_timelong_lock.release()
return
def main(threadcount):
"""起多多线程执行计算"""
for i in range(0,threadcount):
d=deferToThread(calc,2000000)
d.addCallback(callback)
#reactor.callLater(60,reactor.stop)
reactor.run()
if __name__=="__main__":
main(4)