【问题标题】:Python: How to keep variable memory location across assignment?Python:如何在分配中保持变量内存位置?
【发布时间】:2011-03-10 16:39:02
【问题描述】:

我对 Python 还是很陌生,所以如果这个问题很愚蠢,请原谅我。我无法通过 Google 找到答案...

我在我的代码中使用 PyFFTW,它有一个规划阶段,您可以在其中将两个变量(源/目标)传递给它,这是您从/到的转换。然后,当您调用 FFT 时,它将在计划阶段这些变量所在的确切内存空间上运行。因此,对变量所做的任何操作都需要完成,以便这两个变量在内存中的位置不会改变。 我找到了运算符*=+= 等,它们对标准数学运算符执行此操作。 但是在我的程序中,我需要对变量应用一个函数,它应该将它返回到相同的内存位置。 怎么办?!

我最初使用切片的方式如下:

a[:] = func(a)[:]

但是我刚刚意识到,这非常慢(我的代码慢了大约 10%)。 那么有人知道该怎么做吗?

非常感谢任何帮助。提前致谢!

【问题讨论】:

  • 简而言之,您对 Python 中的内存细节绝对没有权力。甚至切片分配也可以轻松触发重新分配,从而移动项目。一些实现可能会停止世界并压缩整个堆,只是为了在循环中间进行。
  • 嗨。我对这个概念感到非常惊讶,因为这会使 PyFFTW 工作方式的想法完全无用,不是吗?!
  • 是的,这就是为什么我听到它感到惊讶。如果您坚持使用 CPython(因为 PyFFTW 是一个 C 库,无论如何它都仅限于此)并且不要调整列表的大小,那么您可能会很好。它只是更花哨的垃圾收集器,并且列表超出了已经分配的大小(大多数数据结构都有一点过度分配,所以你可以在重新分配之前有一些项目),这可能会导致令人讨厌的讨厌的问题(来自 segfaults 默默地改变未使用的内存以静默数据损坏)。
  • 好的。这非常令人失望,因为我必须寻找一种完全不同的方式来做这件事,因为我的算法实际上是在进行数百万次 FFT 和逆 FFT……整个算法都基于此!
  • 一个列表(以及所有其他集合)只分配这么多内存。当您添加更多项目时,您需要重新分配(即从操作系统获取一个新的、完全不相关的内存块并将您的东西复制到那里),因为您无法随心所欲地调整现有内存块的大小。见the source。其他所有语言都存在同样的问题。但是在 C 中,您知道何时重新分配,因为没有人为您进行内存管理。你仍然可以做你想做的事,你只需要事先制作一个适当大小的列表。

标签: python memory variables fftw


【解决方案1】:

这是你想要做的事情吗?

def time10(a):
  """ multiple the elements by 10 in-place """
  for i in xrange(len(a)):
    a[i] *= 10
  # returning a is optional. I think it maybe useful for use to chain the operation
  return a

>>> a = range(10)
>>> time10(a)
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> a
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> b = range(10)
>>> time10(time10(b))
[0, 100, 200, 300, 400, 500, 600, 700, 800, 900]
>>> b
[0, 100, 200, 300, 400, 500, 600, 700, 800, 900]
>>>

您的原始代码在返回后复制数组。这通常不是一种有用的做法,并且会导致运行时间变慢。

【讨论】:

  • 您好,感谢您的回复。实际上我想做的是相关的,是的。如果我会做 a*=b 而不是 a=a*b 它会给我相同的结果,但是 a*=b 不会更改 'a' 的内存位置,而后者会。所以问题是,我如何在不改变“a”的内存位置的情况下做类似 a=ifftshift(a) 的事情。 'ifftshift' 是一个内置函数,我不想重新实现,因此 zerocrates 建议的直接突变将不起作用。有什么想法吗?
【解决方案2】:

您的变量是可变类型,因此您的函数可以直接对其进行操作。

您仍然无法使用将要创建副本和/或进行新分配的函数和运算符(您已经无法使用的相同),但您的函数参数的直接突变将是在函数外可见。

【讨论】:

  • 这是一个很好的观点。我没有考虑过 - 我猜是因为来自 MATLAB 背景。我会尝试这样做,因为我猜它也更适合面向对象编程......到目前为止,我总是从我的方法中返回“self”,我认为这在风格上不是很漂亮。
  • 嗨。我刚刚意识到我真的不能按照你的建议做,因为在我的代码中我使用 Numpy 的 fftshift/ifftshift 函数,所以我会有类似的东西:a=fftshift(a) 现在我不想弄乱fftshift 的内部工作原理,所以我不能直接突变。那么你知道在不改变'a'的内存位置的情况下进行分配的任何方法吗?我会很感激的!
【解决方案3】:

如何使用局部值并将其引用到全局值。我想它可以更快...

global a
a = []
def test(): 
    global a
    b = [1,2,3,4]
    a = b
....

嗯.. 我还得用 cProfiler 测试它

【讨论】:

    【解决方案4】:

    所以最后我找不到令人满意的解决方案。 我最初最终使用了上面 delnan 提出的解决方案

    a[:] = func(a)[:]
    

    并预先分配一定大小的数组。 很抱歉将此添加为我的答案,因为我不知道如何/是否可以接受 delnans cmets 作为答案...

    【讨论】:

      猜你喜欢
      • 2020-11-08
      • 2016-04-19
      • 2013-09-30
      • 1970-01-01
      • 2014-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-20
      相关资源
      最近更新 更多