numpy float:比内置的算术运算速度慢10倍?

2024-04-25 12:10:02 发布

您现在位置:Python中文网/ 问答频道 /正文

对于下面的代码,我得到了非常奇怪的计时:

import numpy as np
s = 0
for i in range(10000000):
    s += np.float64(1) # replace with np.float32 and built-in float
  • 内置浮子:4.9秒
  • 浮动64:10.5秒
  • 浮动32:45.0秒

为什么float64float慢两倍?为什么float32比float64慢5倍?

有什么方法可以避免使用np.float64,并让numpy函数返回内置的float,而不是float64的惩罚吗?

我发现使用numpy.float64比Python的float慢得多,numpy.float32甚至慢得多(即使我在32位计算机上)。

numpy.float32在我的32位计算机上。因此,每次我使用各种numpy函数,比如numpy.random.uniform,我都会将结果转换为float32(以便以32位精度执行进一步的操作)。

有没有办法在程序或命令行中设置单个变量,并使所有numpy函数返回float32,而不是float64

编辑1:

numpy.float64在算术计算中比float慢10倍。很糟糕的是,即使在计算之前转换成float和back,程序运行速度也会提高3倍。为什么?我能做些什么来修理它吗?

我想强调的是,我的时间安排不是由于以下原因:

  • 函数调用
  • numpy和python float之间的转换
  • 对象的创建

我更新了我的代码,使它更清楚的问题所在。在新代码中,我看到使用numpy数据类型的性能下降了10倍:

from datetime import datetime
import numpy as np

START_TIME = datetime.now()

# one of the following lines is uncommented before execution
#s = np.float64(1)
#s = np.float32(1)
#s = 1.0

for i in range(10000000):
    s = (s + 8) * s % 2399232

print(s)
print('Runtime:', datetime.now() - START_TIME)

时间安排如下:

  • 浮动64:34.56s
  • 浮动32:35.11s
  • 浮子:3.53s

就为了这个,我还试着:

从datetime导入datetime 将numpy导入为np

START_TIME = datetime.now()

s = np.float64(1)
for i in range(10000000):
    s = float(s)
    s = (s + 8) * s % 2399232
    s = np.float64(s)

print(s)
print('Runtime:', datetime.now() - START_TIME)

执行时间是13.28秒;实际上,将float64转换为float并将其转换回比按原样使用快3倍。尽管如此,转换还是要付出代价的,因此总的来说,它比纯python慢3倍多。

我的机器是:

  • 英特尔酷睿2双核T9300(2.5GHz)
  • WinXP Professional(32位)
  • ActiveState Python 3.1.3.5版
  • 纽比1.5.1

编辑2:

谢谢你的回答,它们帮助我理解如何处理这个问题。

但我仍然想知道(可能基于源代码)下面的代码在使用float64时运行速度比使用float时慢10倍的确切原因。

编辑3:

我在Windows 7 x64(intelcorei7930@3.8GHz)下重新运行了代码。

同样,代码是:

from datetime import datetime
import numpy as np

START_TIME = datetime.now()

# one of the following lines is uncommented before execution
#s = np.float64(1)
#s = np.float32(1)
#s = 1.0

for i in range(10000000):
    s = (s + 8) * s % 2399232

print(s)
print('Runtime:', datetime.now() - START_TIME)

时间安排如下:

  • 浮动64:16.1s
  • 浮动32:16.1s
  • 浮子:3.2s

现在两个np浮点(64或32)都比内置的float慢5倍。不过,还是有很大的不同。我在想它是从哪里来的。

编辑结束


Tags: 代码inimportnumpyfordatetimetimenp
3条回答

也许,这就是为什么应该直接使用Numpy而不是使用循环。

s1 = np.ones(10000000, dtype=np.float)
s2 = np.ones(10000000, dtype=np.float32)
s3 = np.ones(10000000, dtype=np.float64)

np.sum(s1) <-- 17.3 ms
np.sum(s2) <-- 15.8 ms
np.sum(s3) <-- 17.3 ms

在这样一个沉重的循环中操作Python对象,不管它们是floatnp.float32,总是很慢的。NumPy对向量和矩阵的操作很快,因为所有的操作都是由用C编写的库的一部分对大块数据执行的,而不是由Python解释器执行的。在解释器和/或使用Python对象中运行的代码总是很慢,使用非本机类型会使其速度更慢。这是意料之中的。

如果你的应用程序很慢,你需要优化它,你应该试着把你的代码转换成一个直接使用NumPy的向量解决方案,并且速度很快,或者你可以使用Cython等工具在C中创建一个循环的快速实现

CPython浮点以块的形式分配

比较numpy标量分配和float类型的关键问题是,CPython总是为大小为N的块中的floatint对象分配内存

在内部,CPython维护一个链接的块列表,每个块都足够大,可以容纳Nfloat个对象。当您调用float(1)时,CPython检查当前块中是否有可用空间;如果没有,则分配一个新块。一旦在当前块中有空格,它只需初始化该空格并返回指向它的指针。

在我的机器上,每个块可以容纳41个float对象,因此第一个float(1)调用有一些开销,但是随着内存的分配和准备就绪,下一个40运行得更快。

慢速numpy.float32与numpy.float64比较

在创建标量类型时,numpy似乎有两条路径:fast和slow。这取决于标量类型是否有一个Python基类,它可以将其推迟到该基类进行参数转换。

由于某些原因,numpy.float32被硬编码为采用较慢的路径(defined by the ^{} macro),而numpy.float64有机会采用较快的路径(defined by the ^{} macro)。注意,scalartypes.c.src是一个模板,它在构建时生成scalartypes.c

你可以在Cachegrind中看到这一点。我还提供了屏幕截图,显示了构造float32float64的调用次数:

float64走捷径

float64 takes the fast path

float32走慢路

float32 takes the slow path

已更新-哪种类型采用慢速/快速路径可能取决于操作系统是32位还是64位。在我的测试系统Ubuntu Lucid 64位上,float64类型比float32快10倍。

相关问题 更多 >

    热门问题