Windows上不一致的Python性能



我有一些Python 2.7代码,我正在工作,它在任何*nix类型的系统上工作得很好。然而,在windows上,同一段代码的执行时间却大不相同。注意下面的调试输出。T是每次通过的总时间,s是生成数据的时间,u是将数据通过串行发送到我的设备的时间(全部以毫秒为单位)。

t: 9 - s: 3 - u: 6
t: 14 - s: 9 - u: 5
t: 9 - s: 3 - u: 6
t: 9 - s: 3 - u: 6
t: 15 - s: 8 - u: 7
t: 14 - s: 9 - u: 5
t: 11 - s: 5 - u: 6
t: 15 - s: 9 - u: 6
t: 14 - s: 9 - u: 5
t: 13 - s: 8 - u: 5
t: 15 - s: 9 - u: 6
t: 15 - s: 9 - u: 6
t: 14 - s: 8 - u: 6
t: 11 - s: 6 - u: 5
t: 11 - s: 5 - u: 6
t: 15 - s: 8 - u: 7
t: 15 - s: 10 - u: 5
t: 7 - s: 2 - u: 5
t: 15 - s: 9 - u: 6
t: 15 - s: 9 - u: 6
t: 13 - s: 7 - u: 6
t: 12 - s: 7 - u: 5
t: 12 - s: 6 - u: 6
t: 15 - s: 9 - u: 6
t: 8 - s: 2 - u: 6
t: 14 - s: 9 - u: 5
t: 15 - s: 9 - u: 6
t: 14 - s: 9 - u: 5
t: 15 - s: 9 - u: 6
t: 14 - s: 8 - u: 6
t: 14 - s: 9 - u: 5
t: 14 - s: 9 - u: 5
t: 9 - s: 4 - u: 5
t: 11 - s: 5 - u: 6

串行发送时间不是问题,通常非常一致。是"s"步骤,它实际生成有问题的数据,在任何地方花费2到9毫秒。相当大的秋千!在Debian(甚至在树莓派上运行)上,这个部分花费的时间非常一致,为11-12毫秒。

还有很多其他的代码但是用"s"时间表示的步骤基本上是这样的:

    buf = [wheel_helper(self._vector[y][x], h, s) for y in range(h) for x in range(w)]
    buf = [i for sub in buf for i in sub]
    self._led.setBuffer(buf)

它在矩阵上生成彩虹图案,其中颜色基于其与中心的距离。但这就是它每次所做的全部。我看不出它为什么会随时间如此剧烈地变化。

任何想法吗?

Update:您通常可以忽略我为"s"步骤运行的代码。这只是许多的一个例子,所有这些都在非常可变的时间内运行。有些使用范围,有些没有。这是全面的,但总是一个问题。

更新2:

好吧,我做了一些进一步的测试,并做了一个非常简单的例子,没有使用范围!它计算斐波那契数列的前1000个元素1000次。很简单,对吧?但在Windows上,最快运行和最慢运行之间的差异将延长近375% (Max/Min在下面的示例输出中)。所有计时值都以毫秒为单位。

import time
import math
min = 10
max = 0
avg = 0
sum = 0
count = 0
def msec():
    return time.clock() * 1000.0
def doTime(start):
    global min
    global max
    global avg
    global sum
    global count
    diff = msec() - start
    if diff < min: min = diff
    if diff > max: max = diff
    sum += diff
    avg = sum/count
    print "Curr {:.3f} | Min {:.3f} | Max {:.3f} | Max/Min {:.3f} | Avg {:.3f}".format(diff, min, max, max/min, avg)

h = 24
w = 24
while count < 1000:
    start = msec()
    #calculate the first 1000 numbers in the fibonacci sequence
    x = 0
    while x < 1000:
        a = int(((((1 + math.sqrt(5)) / 2) ** x) - (((1 - math.sqrt(5)) / 2) ** (x))) / math.sqrt(5))
        x+=1
    count+=1
    doTime(start)

结果是Mac不能免疫,但在最慢的情况下,只有75%的时间更长。我试着在Linux上运行,但它不会做微秒计时分辨率,似乎所以数字四舍五入到最接近的ms。

Windows: Curr 2.658 | Min 2.535 | Max 9.524 | Max/Min 3.757 | Avg 3.156
Mac: Curr 1.590 | Min 1.470 | Max 2.577 | Max/Min 1.753 | Avg 1.554

我认为这是由于范围。旧版本的python (2.X)同时具有rangexrange。但是xrangerange更有效,因为xrange只在需要时生成列表(即返回生成器),而range生成整个列表(因此效率很低,假设您有一个从1到100000的列表)

因此,如果您的列表大小增加,使用range可能是您的进程变慢的原因。

我看不出有什么问题。您有执行串行IO的代码,这将阻塞您的进程并可能调用调度器。如果发生这种情况,它将首先把控制权交给另一个进程,只有当这个进程的产量或超过它的时间片时,它才会重新安排你的进程。

您的问题是:您正在运行的系统的调度程序时间片的大小是多少?我相信这会让你对正在发生的事情有一个深入的了解。

最新更新