python - 遍历类对象数组 VS 包含数组的类对象

标签 python numpy performance numba

我想创建一个用于多代理模拟的程序,我正在考虑是否应该使用 NumPy 或 numba 来加速计算。基本上,我需要一个类来存储代理的状态,并且我将拥有超过 1000 个此类的实例。在每个时间步中,我将对所有实例执行不同的计算。我正在考虑两种方法:

Numpy 向量化:

拥有 1 个带有多个 NumPy 数组的类,用于存储所有代理的状态。因此,在模拟过程中,我始终只有 1 个类实例。通过这种方法,我可以简单地使用 NumPy 向量化来执行计算。但是,这将使特定代理的运行功能变得困难,我需要一个额外的类来存储每个代理的索引。

Class agent:
   def __init__(self):
      self.A = np.zeros(1000)
      self.B = np.zeros(1000)
   def timestep(self):
      return self.A + self.B

Numba jitclass:

使用 numba jitclass 装饰器编译代码。通过这种方法,我可以应用更标准的 OOP 格式代码,因为一个类实例代表一个代理。但是,我不确定循环多个 jitclass 实例(比如说 1000 或更多)的性能。

@jitclass
class agent:
   def __init__(self):
      self.A = 0
      self.B = 0
   def timestep(self):
      return self.A + self.B

我想知道哪种方法更快。

最佳答案

这个问题被称为“AoS VS SoA”,其中 AoS 表示结构数组,而 SoA 表示数组结构。您可以找到有关此的一些信息 here . SoA 不如 AoS 用户友好,但通常效率更高。当您的代码可以受益于使用 SIMD 指令 时尤其如此。当您处理许多大数组(例如 >=8 个大数组)或执行许多标量随机内存访问时,AoS 和 SoA 都不是高效的。在这种情况下,最好的解决方案是使用小型数组结构数组 (AoSoA),以便更好地使用 CPU 缓存,同时仍然能够从 SIMD 中获益。然而,AoSoA 很乏味,因为复杂性明显是非平凡算法的代码。请注意,访问的字段数量对于最佳解决方案的选择也很重要(例如,如果只有一个字段被频繁读取,那么 SoA 是完美的)。

OOP is generally rather bad when it comes to performance部分是因为这个。另一个原因是经常使用虚拟调用多态性,但并不总是需要。 OOP 代码往往会导致大量缓存未命中,并且优化大量使用 OOP 的大型代码通常是一团糟(有时会导致重写目标软件的大部分或代码变得非常慢).为了解决这个问题,data oriented design可以使用。这种方法已成功用于大幅加速来自 video games 的大型代码库(例如 Unity )到网络浏览器渲染器(例如 Chrome )甚至关系数据库。在高性能计算 (HPC) 中,OOP 通常很少被使用。面向对象设计与 SoA 而不是 AoS 的使用密切相关,因此可以更好地使用缓存并从 SIMD 中获益。更多信息,请阅读this相关帖子。

总而言之,我建议您在您的案例中使用第一个代码 (SoA)(因为您只有两个数组,而且它们不是那么大)。

关于python - 遍历类对象数组 VS 包含数组的类对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71101579/

相关文章:

c# - 将文本文件加载到 RichTextBox 的最快方法是什么?

java - Android onTouchListener Action_Up-MotionEvent 在第一次恢复后延迟

python - 如何以编程方式访问 coverage.py 结果?

c# - 将内存中的位图图像转换为 4 维数组,如 numpy

python - 语法错误 : Generator expression must be parenthesized

python - 执行矩阵乘法时出现内存错误

python - 如何快速创建一个 numpy 或 pandas 二维数组,其中两个轴都在一个范围内并且值是一个产品?

.net - 在 PerfMon 实例中选择正确的 AppPool

python - 使用 matplotlib 绘制大量点并耗尽内存

python - Numpy:从两个向量(或一个向量本身)的笛卡尔积创建一个矩阵,同时将一个函数应用于所有对