Windows上Python性能不一致
我在写一些Python 2.7的代码,这段代码在任何类Unix系统上运行得很好。但是在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)
它在一个矩阵上生成一个彩虹图案,颜色是根据离中心的距离来决定的。但这就是它每次做的所有事情。我看不出为什么它的执行时间会有这么大的波动。
有什么想法吗?
更新:你可以一般性地忽略我在“s”步骤中运行的代码。这只是众多例子中的一个,所有这些例子的运行时间都非常不稳定。有些使用了range,有些没有。情况各不相同,但总是个问题。
更新2:
好吧,我做了一些进一步的测试,做了一个非常简单的例子,没有使用range!它计算了前1000个斐波那契数列的元素,重复1000次。听起来很简单,对吧?但是在Windows上,最快和最慢的运行时间差别几乎达到了375%(下面示例输出中的最大值/最小值)。所有的时间值都是毫秒。
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上运行,但似乎它无法做到微秒级的时间分辨率,所以数字被四舍五入到最接近的毫秒。
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
2 个回答
我看不出有什么问题。你的代码在进行串行输入输出,这会让你的程序停下来,可能还会影响到系统的调度器。如果发生这种情况,系统会先把控制权交给另一个程序,只有当那个程序让出控制权或者超出它的时间片时,才会重新调度你的程序。
你需要考虑的是:你所运行的系统的调度时间片有多大?我觉得了解这个信息会帮助你更好地理解发生了什么。
我觉得这跟 range 有关。在旧版本的 Python(2.X)中,有 range 和 xrange 这两个功能。其实 xrange 比 range 更高效,因为 xrange 只在需要的时候才生成列表(也就是说,它返回的是一个生成器),而 range 是一次性生成整个列表(这样效率就低了,想象一下如果你要生成从 1 到 100000 的列表)。
所以,如果你的列表越来越大,使用 range 可能就是导致你的程序变慢的原因。