【问题标题】:Inconsistent Execution Time in Python on all systemsPython 在所有系统上的执行时间不一致
【发布时间】:2014-07-15 15:20:36
【问题描述】:

让我对 python 发疯的东西……我以前以为是just Windows,但我错了。我可以拥有完全相同的代码并多次运行它,但它的执行时间却大相径庭。以如下测试代码为例:

import math
def fib(count):
    x = 0
    while x < count:
        a = int(((((1 + math.sqrt(5)) / 2) ** x) - (((1 - math.sqrt(5)) / 2) ** (x))) / math.sqrt(5))
        x+=1

if __name__ == '__main__':  
    import timeit

    t = timeit.Timer("fib(1250)", setup="from __main__ import fib",)
    #print t.timeit(10)
    count = 10000
    results = t.repeat(count, 1)
    min = 0xFFFF
    max = 0
    sum = 0
    for i in results:
        i = i*1000.0
        if i < min: min = i
        if i > max: max = i
        sum+=i

    print "Min {:.3f} | Max {:.3f} | Max/Min {:.3f} | Avg {:.3f}".format(min, max, max/min, sum/count)

基本上,它会生成 fibonacii 的前 1250 个元素 10,000 次,并使用 timeit 来获取每次运行所需的时间。然后我合并这些时间并找到最小值、最大值、平均值以及最小值和最大值之间的方差(如果你愿意的话,可以是散布)。

结果如下:

Windows: Min 3.071 | Max 8.903 | Max/Min 2.899 | Avg 3.228
Mac OS:  Min 1.531 | Max 3.167 | Max/Min 2.068 | Avg 1.621
Ubuntu:  Min 1.242 | Max 10.090 | Max/Min 8.123 | Avg 1.349

因此,Linux 是最快的,但也有最大的差异。很多。但是它们都可以有相当大的波动:Mac 只有 200%,但 Windows 为 290%,Linux 为 810%!

实际上执行所需的时间有很大不同吗?是timeit不够准确吗?还有什么我想念的吗?我在生成动画方面做了很多工作,我需要尽可能一致的时间。

【问题讨论】:

  • 根据计时器和您的实现,测量的时间可能会受到系统上运行的其他进程的影响。对于挂钟计时器尤其如此。
  • 看...这就是我的想法(实际执行时间是相当恒定的),但测量的时间在它们的变化量上是相当一致的。
  • 您将时间乘以 1000。而是通过重复代码来执行此操作,以使一个测试运行接近 1 秒。
  • @Adam Haile - 可能想看看这个:stackoverflow.com/questions/15176619/…
  • @AdamHaile:Python 可能会也可能不会很慢,这实际上取决于您的代码和库。如果您正在计算事物,使用 NumPy 可能会产生巨大的影响。 Python 本身不适用于数值繁重的工作。另一方面,Python 非常擅长处理复杂的数据结构(字典、集合、列表)。

标签: python performance


【解决方案1】:

你测量的时间很短,然后某处发生的一点点事情都会产生很大的影响。

我在我的机器(OS X、Core i7、Python 2.7)上运行了你的测试脚本并制作了results 的绘图:

您可以看到,大多数情况下计时结果非常一致,但也有一些孤立的算法事件需要更多时间(因为发生了其他事情)。


我对你的计时程序做了一个微小的调整:

results=t.repeat(10, 1000)

所以,现在我们正在计时运行 1000 个函数调用。总时间自然是一样的(10000次调用):

现在您可以看到性能更加可预测。可能你的部分时间不稳定是由于时间方法,而不是由于真正不同的时间来执行任何事情。在现实世界的操作系统环境中,毫秒级的计时是很困难的。即使您的计算机“什么都不做”,它仍然在切换任务、做后台作业等。


我知道最初的目的不是计算斐波那契数。但如果是这样,那么选择正确的工具就会有所不同:

import numpy as np

def fib(count):
    x = np.arange(count)
    a = (((1 + np.sqrt(5))/2) ** x - ((1 - np.sqrt(5)) / 2) ** x) / np.sqrt(5)
    a = a.astype('int')

这给出了:

Min 0.120 | Max 0.471 | Max/Min 3.928 | Avg 0.125

十倍速度提升。


关于此答案中的图像,它们是用matplotlib 绘制的。第一个是这样完成的:

import matplotlib.pyplot as plt

# create a figure
fig = plt.figure()
# create axes into the figure
ax = fig.add_subplot(111)
# plot the vector results with dots of size 2 (points) and semi-transparent blue color
ax.plot(results, '.', c=(0, 0, 1, .5), markersize=2)

参见matplotlib 的文档。使用IPythonpylab 最容易上手。

【讨论】:

  • 不错的图表...你是怎么做到的?所以,嗯......也许我是对的,我习惯于时间一致的原因是我在没有 UI 并且几乎没有运行服务的 Raspberry Pi 上运行。我的 python 获得了 90% 以上的 CPU...
  • 很公平......我有点认为情况会如此,一次只运行 1 次并不是最好的方法。我遇到的问题是我正在尝试为动画生成帧并提供一致的帧速率。因此,单帧步骤中的任何变化都会使其变得不稳定。解决这个问题的唯一方法似乎是将帧时间限制为大于最大生成时间的时间。它很流畅,但速度较慢。
  • @AdamHaile:如果您查看运行时间较长的百分比变化,它会很小。很容易得到个位数的毫秒延迟,但十毫秒的延迟已经很长了。因此,毕竟您可能不会在动画方面遇到麻烦。但是,如果您可以提前计算动画,您可能会考虑使用几帧的缓冲区。 - 当您运行动画代码时,为每帧计算的开始和结束记录真正的挂钟时间戳。然后您会看到是否存在与操作系统相关的额外延迟。
  • timeit.Timer 还接受一个“数字”参数来快速计时 X 次迭代的单次运行。 timed_execution = timeit.Timer("fib(1250)", setup="from __main__ import fib", number=1000)
【解决方案2】:

我制作了一个类似于@drV 的情节(给他投票,他是第一个!) - 不同之处在于我对结果进行了排序,以便您可以看到趋势线。提示是,即使最大值很高,平均值也很低,所以最后会有一些异常值。

我使用 pylab 只需将其添加到底部:

from pylab import *
results.sort()
plot(range(len(results)),results)
show()

【讨论】:

  • 一个明确的 +1 显示分布的好方法! (使用from pylab import * 接口可能是-.01 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-23
  • 2016-07-27
  • 2019-04-28
  • 1970-01-01
  • 2010-10-12
  • 1970-01-01
  • 2021-12-28
相关资源
最近更新 更多