Numpy:每次操作的内存分配?

时间:2015-11-04 17:55:54

标签: python numpy

numpy是否为您在矩阵上执行的每个操作分配新矩阵?

例如:

< Connector 
port="8443" 
protocol="HTTP/1.1" 
SSLEnabled="true"
maxThreads="150" 
scheme="https" 
secure="true"
clientAuth="false" 
sslProtocol="TLS" 
keystoreFile="conf/Certificate/keystore.jks"
keystorePass="<PASSWORD>" 
/>

切片操作:

A = np.random.rand(10, 20)
A = 2 * A  # Operation 1: Is a copy of A made, and a reference assigned to A?
B = 2 * A  # Operation 2: Does B get a completely different copy of A?
C = A      # Operation 3: Does C get a reference to A?

链式操作怎么样?

A[0, :] = 3

Numpy是一个很棒的图书馆,但我只是想知道引擎盖下发生了什么。我的直觉说切片操作会修改内存视图,但我不了解任务。

2 个答案:

答案 0 :(得分:3)

请记住,numpy数组是一个Python对象。 Python不断创建和删除对象。该数组的属性显示在.FLAGS.__array_interface__字典中,例如shapedtype。占用(可能)大量内存的属性是数据缓冲区。它可能是几个字节长,或者可能是MB。

在可能的情况下,numpy操作会尝试避免复制数据缓冲区。建立索引时,如果可能,它将返回view。我认为文档可以很好地比较视图和副本。

但是视图与Python引用不同。共享引用意味着两个变量(或列表或字典中的指针)指向同一个Python对象。 view是一个不同的数组对象,但是与另一个数组共享数据缓冲区的对象。副本有自己的数据缓冲区。

在您的示例中:

A = np.random.rand(10, 20)

A是指向数组对象的变量。该对象有一个包含200个浮点数(200 * 8字节)的数据缓冲区。

A = 2 * A  # Operation 1: Is a copy of A made, and a reference assigned to A?

2*A使用新的数据缓冲区创建一个新对象。它的所有数据值都不能与原始A共享。 A=...重新分配A变量。旧的A对象已丢失,最终内存被垃圾收集。

B = 2 * A  # Operation 2: Does B get a completely different copy of A?

2*A对新的A数组进行操作。该对象已分配给BA保持不变。

C = A      # Operation 3: Does C get a reference to A?

是的,这只是普通的Python分配。 C引用与A相同的对象。 id(C)==id(A)

B = A[1,:]  #  B is a view

B是对新数组对象的引用。但是该对象与A共享数据缓冲区。这是因为只需从不同的点开始,并使用不同的shape,就可以在缓冲区中找到所需的值。

A[0, :] = 3

此LHS切片将更改A值的子集。它类似于:

B = A[0, :]
B = 3

但是LHS和RHS切片之间存在明显的差异。在LHS上,你必须更加注意何时获得副本而不是视图。我已经看到过这种情况,尤其是A[idx1,:][:,idx2] = 3等表达式。

D = A * B * C 

在这样的计算中制作了多少个中间副本的细节都隐藏在numpy C代码中。最安全的做法是假设它像:

temp1 = A*B
temp2 = temp1*C
D = temp2
(temp1 goes to garbage)

对于普通计算,不值得担心这些细节。如果你真的在追求速度,你可以对替代品做timeit。偶尔我们会得到关于提供memory errors的操作的问题。进行搜索以获得有关这些内容的更多详细信息。

答案 1 :(得分:2)

是的,它创建了新的数组。除了C. C和A指向相同的记忆。

您可以自己测试所有这些。尝试使用id(A)命令查看内存A指向的位置。此外,只需创建一个较小的结构并修改它的一部分,然后查看A,B和/或C是否也更新。