Timeit显示常规python比numpy快?

Timeit显示常规python比numpy快?,python,performance,numpy,timeit,Python,Performance,Numpy,Timeit,我正在为一个游戏编写一段代码,该代码使用游戏中的坐标位置计算屏幕上所有对象之间的距离。最初,我打算使用基本Python和列表来实现这一点,但由于需要计算的距离数量将随着对象数量的增加而呈指数增长,因此我认为使用numpy可能会更快 我对numpy不是很熟悉,我一直在用它进行基本代码位的实验。我编写了一些代码来计算同一个函数在numpy和常规Python中完成计算所需的时间,numpy似乎总是比常规Python花费更多的时间 功能非常简单。它从1.1开始,然后递增200000次,最后一个值加上0.

我正在为一个游戏编写一段代码,该代码使用游戏中的坐标位置计算屏幕上所有对象之间的距离。最初,我打算使用基本Python和列表来实现这一点,但由于需要计算的距离数量将随着对象数量的增加而呈指数增长,因此我认为使用numpy可能会更快

我对numpy不是很熟悉,我一直在用它进行基本代码位的实验。我编写了一些代码来计算同一个函数在numpy和常规Python中完成计算所需的时间,numpy似乎总是比常规Python花费更多的时间

功能非常简单。它从1.1开始,然后递增200000次,最后一个值加上0.1,然后找到新值的平方根。这不是我在游戏代码中实际要做的,它将涉及从位置坐标中找到总距离向量;这只是我做的一个快速测试。我已经读到,数组的初始化在NumPy中需要更多的时间,所以我将NumPy和python数组的初始化都移到了它们的函数之外,但是python仍然比NumPy快

下面是一段代码:

#!/usr/bin/python3

import numpy
from timeit import timeit
#from time import process_time as timer
import math

thing = numpy.array([1.1,0.0], dtype='float')
thing2 = [1.1,0.0]

def NPFunc():

    for x in range(1,200000):
        thing[0] += 0.1
        thing[1] = numpy.sqrt(thing[0])


    print(thing)
    return None


def PyFunc():

    for x in range(1,200000):
        thing2[0] += 0.1
        thing2[1] = math.sqrt(thing2[0])

    print(thing2)
    return None


print(timeit(NPFunc, number=1))
print(timeit(PyFunc, number=1))
它给出了这个结果,这表明普通Python的速度快了3倍:

[ 20000.99999999    141.42489173]
0.2917748889885843

[20000.99999998944, 141.42489172698504]
0.10341173503547907

我做错了什么吗?这个计算是不是太简单了,不能作为numpy的一个好测试?

你比较错了

a_list = np.arange(0,20000,0.1)
timeit(lambda:np.sqrt(a_list),number=1)
我做错了什么吗?这个计算是不是太简单了,对NumPy来说不是一个好的测试

这并不是说计算很简单,而是你没有利用NumPy

最重要的是,由于数组中的值存储为本机值,因此NumPy函数不需要取消对它们的装箱,从Python浮点中取出原始的C double,然后用新的Python浮点重新装箱,就像任何Python数学函数必须做的那样

但你也没有这么做。事实上,这项工作是加倍的:将数组中的值作为一个浮点值进行装箱,然后将其传递给一个函数,该函数必须对其进行拆箱,然后重新对其进行装箱以返回结果,然后将其存储回数组中,再次对其进行拆箱

同时,由于np.sqrt设计用于处理数组,因此它必须首先检查要传递给它的内容的类型,并决定是否需要在数组上循环,或者取消装箱并重新装箱单个值,而math.sqrt只接受单个值。当您在200000个元素的数组上调用np.sqrt时,该类型开关的附加成本可以忽略不计,但当您每次都通过内部循环执行此操作时,情况就不同了

所以,这不是一个不公平的测试

您已经演示了使用NumPy一次提取一个值,一次处理一个值,然后一次存储一个值到数组中,这比不使用NumPy要慢


但是,如果你将其与实际利用NumPy进行比较——例如,创建一个包含200000个浮点的数组,然后在该数组上调用np.sqrt,而不是在每个数组上循环并调用math.sqrt,那么你将证明按照预期的方式使用NumPy比不使用更快。

作为旁注,在你计划的东西里面打印通常是个坏主意。打印东西所需的时间变化很大,也可能比实际工作所需的时间更长。在这种情况下,这可能没什么大不了的,因为你正在使用number=1,并且在函数中做了很多工作,但是最好还是去掉print调用。这是有道理的。另外,与其在函数中循环200000次并使用number=1,不如让timeit至少控制其中的一部分,例如。,循环2000次,美国编号=100。这给了它更多的工作机会。不过,我还是怀疑在这种特殊情况下,它会有多大的不同。最后一件事:用数组替换列表,用数组函数替换循环,这样可以获得恒定的加速因子。这可能是一个令人印象深刻的加速,比如6倍甚至60倍,但如果你的问题是指数增长,那可能只会让你的最大可行N增加1或2…Numpy擅长矢量化命令。使用Numba或Cython编译器,简单循环通常可以获得100-1000倍的系数。这很有意义。我试过上面Joran Beasley评论的代码行,速度明显更快。因此,诀窍是尽可能少地将值创建/加载到numpy数组中,但要使这些数组尽可能大
可以这样,一旦您开始对阵列执行操作,程序就可以高效地在一个大型阵列中运行,而无需启动和停止?@CMB。许多问题可以转化为一系列的元素操作或一次一个数组的操作,因此,如果您可以用NumPy数组来编写它们,您将获得很大的加速。有些问题不能这样写,所以你只能从NumPy中得到开销。除了你仍然可以从大量的浮点对象和海量数据中获得空间优势,这反过来可以在分配、缓存、交换等方面节省大量时间。但是,另一方面,有时你可以懒散地编写非NumPy代码,因此它根本不占用空间,那么,与将普通python值加载到数组中所需的时间相比,计算量的增加有多大的好处呢?对于真正的代码,游戏中的每个对象都将是一个类实例,它包含自己的位置向量。所有对象都将存储在一个列表中。我最初的计划是让一段代码沿着列表向下,找出每个列出的对象到所有其他对象的距离。将所有这些位置转移到NumPy数组并执行计算可能更快还是更慢?@CMB如果有很多这样的对象,将所有这些位置向量存储在一个大的2D数组中可能更快,让类实例只跟踪它们的行索引或对数组中的行的引用,而不是直接保存向量。但是,这取决于您还必须对实例执行什么操作。如果您需要循环代码中某个时间关键部分的所有实例,那么仅将该循环的一部分拉到另一个数组操作可能不会有多大好处;您需要将所有内容移动到数组操作以获得较大的加速。将值从NumPy数组移动到其他NumPy数组是否有任何区别?也就是说,如果我将位置存储在它们各自的类实例中作为NumPy数组,那么将它们转移到更大的数组会更容易,还是只会增加更多工作?