【问题标题】:More memory efficient way to define many objects of the same type定义许多相同类型的对象的内存效率更高的方法
【发布时间】:2023-03-11 01:25:01
【问题描述】:

所以,我正在涉足等离子模拟的世界。现在,虽然我知道顶级模拟是用 fortran 编写的,并且具有超内存效率的子例程和专用代码,但我希望只运行一些低级模拟。

我的问题是,在时变环境(嗯,时间步长)中模拟大量粒子时,跟踪所有数据是一个技巧。我之前使用过多维数组——使用粒子的列号和属性的行号,但是这感觉相当笨拙。但是,它似乎执行得更快。

我最近尝试定义自己的类,但是作为一个 python 新手,我可能以一种非常低效的方式做到了。对于 3 维中的每个粒子,我需要能够存储粒子的位置、速度和力(一旦代码变得更复杂,就有可能添加更多变量)。使用我对类的了解,我定义了一个 particle 对象(我认为),它使我的代码更易于阅读和遵循:

# Define Particle as a class
class particle():
    def __init__(self, index=0, pos=np.array([0, 0, 0]), vel=np.array([0,0,0]), 
                 F=np.array([0, 0, 0])):
        self.index = index      # Particle index (identifier)
        self.pos = pos          # Position 3-vector
        self.vel = vel          # Velocity 3-vector
        self.F = F              # Net force 3-vector (at particle)

因此,我可以轻松地初始化一个包含大量此类对象的数组,并以相当直接的方式修改每个值。然而,正如我所提到的,这对于只涉及几个粒子的模拟运行速度较慢。我将使用我的代码将其与纯面向矩阵的方法进行比较,看看哪种方法更适合大型模拟。

我想我的问题是:以这种方式定义“粒子”是最有效的吗?或者是否有更高效的 CPU/内存方式来定义这样的对象。我想保留它的方法能力(即particle[i].pos = [1,2,3]particle[2].vx[1] = 3),这样我就可以为每个粒子设置值,并通过函数传递它们。请记住,我是 Python 新手,所以我可能不会在处理大型复杂代码方面取得巨大成功。

【问题讨论】:

  • 你在使用 numpy 吗?
  • 是的。我也在使用 matplotlib 进行可视化。
  • @user2357112 好点。在我更新的答案中解决了这个问题。

标签: python arrays class types simulation


【解决方案1】:

__slots__节省内存

一种节省内存的方法是使用slots

class Particle():  # Python 3
    __slots__ = ['index', 'pos', 'vel', 'F']
    def __init__(self, index=0, pos=None, vel=None, F=None):
        # Particle index (identifier)
        self.index = index      
        # Position 3-vector
        self.pos = np.array([0, 0, 0]) if pos is None else pos    
        # Velocity 3-vector
        self.vel = np.array([0,0,0]) if vel is None else vel   
        # Net force 3-vector (at particle)
        self.F = np.array([0, 0, 0]) if F is None else F        

来自文档:

可以为此类变量分配一个字符串、可迭代的或具有实例使用的变量名的字符串序列。 __slots__ 为声明的变量保留空间,并防止为每个实例自动创建 __dict____weakref__

旁注:我通过将mutable default argument problem 设置为None 并在__init__() 中为None 值创建一个新的NumPy 数组来修复mutable default argument problem

无法向实例添加新属性

一个重要的区别是你不能在实例化之后添加__slots__中没有列出的属性:

p = Particle()

p.new_attr = 45

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-664-a970d86f4ca3> in <module>()
      1 p = Particle()
      2 
----> 3 p.new_attr = 45

AttributeError: 'Particle' object has no attribute 'new_attr'

与没有__slots__的类比较:

class A:   # Python 3
    pass

a = A()
a.new_attr = 10

没有引发异常。

【讨论】:

  • 这看起来很有趣!这是否使我能够在创建后以相同的方式与对象进行交互?另外,“插槽”是如何工作的? (如果你知道) 编辑:谢谢!当我到达有电脑的地方时,我会尝试这样做。我真的很希望继续使用我的课程,因为它让我的代码看起来很漂亮——在 python 中使用矩阵有点让人头疼。
  • 有几个difference。但对于许多实际用途而言,并没有什么大的缺点。
  • 尝试生成 100 个静态粒子的基本实验,我的程序执行速度较慢 with slots 声明:
  • 你如何衡量这个?多年来我一直在使用 Python 进行性能测量,并且有很多事情会扭曲计时结果。
  • 我刚刚使用了一个与 timeit 不同的计时器: from timeit import default_timer as timer start_time = timer() elapsed = timer() - start_time 现在已经用几千个粒子运行了模拟,不幸的是矩阵似乎是最方便的方法。我只需要处理混乱的代码。对于 10,000 个粒子,类需要 0.61 秒,矩阵需要 0.48 秒。一旦我开始移动这些粒子,我想差异只会增加。
【解决方案2】:

听起来你想要享元模式。也许将对象中的一个整数作为索引存储到具有 9 行元素的数组中?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-24
    • 1970-01-01
    • 2022-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-14
    • 2019-05-21
    相关资源
    最近更新 更多