当多线程处理Python中的大型RawArray(Kubuntu 16.10上的2.7.12+)时,我的性能比我预期的要差。该数组在线程之间共享,并且每个线程在其自己的区域上工作而不用担心与其他线程的争用,因此我不需要或希望与该数组发生任何同步/锁定。
如果我用两个线程运行我的测试代码,我得到的性能是一个线程的两倍,正如预期的那样。三个线程并不是很好(执行时间约为37%,而不是预期的33-35),但改进发生了。但是四个线程根本没有任何改进(甚至性能稍差),添加更多线程也几乎没有提供。
这是一个八线程的四核CPU(i4770K),所以也许我不应该期待过去4个线程的更多性能 - 这是正确的吗?
尽管如此,3到4线程的缺乏改善使我感到困惑,预期和实际表现之间的差距(25%对37%)是如此之大,以至于似乎必定出现问题。
关于基础访问是否同步的RawArray对冲文档(例如“设置和获取元素可能是非原子的”)。是否有可能在RawArray中发生某些潜在的同步或其他低效率?还是我误解了一些基本的东西?
以下是我的测试代码获得的结果,显示执行时间与线程数的函数关系;完成了四次运行,坐标互相绘制:
...在该图表中,您可以清楚地看到它在3个线程上撞墙。这是我用来测试的代码;它会创建一个大数组,将其分解为numthreads片段,并将其交给线程进行一些简单的数学运算:
import math
from multiprocessing import Process
from multiprocessing.sharedctypes import RawArray
import multiprocessing
import datetime as dt
def doMath(mpa, startidx, endidx):
for i in range(startidx, endidx):
mpa[i] = (math.pow(2.12354, 5.1341234)*1.234845)/4.1234234 + 1.345345
mpa = RawArray('f', 200000000)
for numthreads in range(1, 9):
threads = []
chunkwidth = int(math.floor(float(len(mpa))/float(numthreads)))
for tc in range(numthreads - 1):
threads.append(Process(target=doMath, args=(mpa, tc*chunkwidth, (tc+1)*chunkwidth)))
threads.append(Process(target=doMath, args=(mpa, (numthreads-1)*chunkwidth, len(mpa))))
starttime = dt.datetime.now()
for i in range(numthreads):
threads[i].start()
for i in range(numthreads):
threads[i].join()
proctime = dt.datetime.now() - starttime
print('num threads: ' + str(numthreads) + ' time: {:.4f}'.format(proctime.total_seconds()) + ' secs')