我有两个函数np_prodslice_prod,它们对形状相同的两个NumPy数组mat1mat2执行相同的逐元素操作.然而,我注意到np_prod函数比slice_prod函数慢.我使用以下代码来测量性能:

import numpy as np
import timeit

shape = (10, 600, 600)
mat1 = np.random.rand(*shape).astype(np.float32)
mat2 = np.random.rand(*shape).astype(np.float32)

def np_prod(mat1, mat2):
    res = mat1.copy()
    res *= -1
    res += 1
    res *= (1 - mat2)
    res *= -1
    res += 1
    return res

def slice_prod(mat1, mat2):
    res = mat1.copy()
    for i in range(res.shape[0]):
        res[i] *= -1
        res[i] += 1
        res[i] *= (1 - mat2[i])
        res[i] *= -1
        res[i] += 1
    return res

N = 400
print("For loop product: ", timeit.timeit("slice_prod(mat1, mat2)", setup="from __main__ import slice_prod, mat1, mat2", number=N))
print("Numpy product: ", timeit.timeit("np_prod(mat1, mat2)", setup="from __main__ import np_prod, mat1, mat2", number=N))

得到的结果是

For loop product:  15.605191999999999
Numpy product:  18.899588700000002

我的NumPy版本是1.24.2.我预计NumPy实现会更快,因为它优化了数组操作,但在这种情况下,for-loop版本似乎更快.有谁能解释为什么会发生这种情况,以及我如何优化np_prod以使速度更快?

(我提供的示例是我的用例的简化版本.在我自己的代码中,性能差异更显著,比如2倍,使用time.perf_count测量)

推荐答案

这是一个缓存使用的问题:原始代码处理14MB的数据,而第二个版本处理每个1.4MB的10个块.

例如,在我的电脑上,CPU的L3缓存是8MB.因此,对于第一个版本,正在处理的数据无法放入缓存,必须在每次操作时从内存中读取.在第二个版本中,在将每个块读取到缓存后,所有操作都可以对缓存中的数据进行操作.

更改代码,以便正在处理的块可以放入L2或L1缓存中,应该会产生更好的性能.

Python相关问答推荐

如何在where或过滤器方法中使用SQLAlchemy hybrid_Property?

为什么自定义pytree aux_data对于jnp.数组来说在.jit()之后跟踪,而对于np.数组来说则不是?

使用Python进行网页抓取,没有页面

按照行主要蛇扫描顺序对点列表进行排序

拆分pandas列并创建包含这些拆分值计数的新列

通过优化空间在Python中的饼图中添加标签

即使在可见的情况下也不相互作用

连接两个具有不同标题的收件箱

将整组数组拆分为最小值与最大值之和的子数组

如何在箱形图中添加绘制线的传奇?

删除最后一个pip安装的包

. str.替换pandas.series的方法未按预期工作

Pandas 都是(),但有一个门槛

Pandas - groupby字符串字段并按时间范围 Select

为什么这个带有List输入的简单numba函数这么慢

为什么以这种方式调用pd.ExcelWriter会创建无效的文件格式或扩展名?

为什么NumPy的向量化计算在将向量存储为类属性时较慢?'

连接一个rabrame和另一个1d rabrame不是问题,但当使用[...]'运算符会产生不同的结果

在www.example.com中使用`package_data`包含不包含__init__. py的非Python文件

为什么常规操作不以其就地对应操作为基础?