请考虑以下代码:
import numpy as np
a = np.zeros(50)
a[10:20:2] = 1
b = c = a[10:40:4]
print b.flags # You'll see that b and c are not C_CONTIGUOUS or F_CONTIGUOUS
我的问题:
是否有办法(只引用b
)使b
和c
连续?
如果np.may_share_memory(b,a)
在此操作后返回False
,则完全正常。
接近但不太合理的事情是:np.ascontiguousarray
/ np.asfortranarray
,因为它们将返回新的数组。
我的用例是我有一个非常大的3D字段存储在numpy.ndarray
的子类中。为了节省内存,我想将这些字段切换到我实际感兴趣处理的域的部分:
a = a[ix1:ix2,iy1:iy2,iz1:iz2]
对子类的切片比ndarray
对象的切片更受限制,但这应该有效并且它将“做正确的事” - 附加在子类上的各种自定义元数据将被转换/按预期保存。不幸的是,因为这会返回一个view
,之后numpy不会释放大数组,所以我实际上并没有在这里保存任何内存。
要完全清楚,我希望完成两件事:
答案 0 :(得分:6)
“唯一真正可靠的方法来确保一个大的 但临时使用内存会将所有资源返回给系统 当它完成时,就是在子进程中发生这种用法 那些渴望记忆的工作会终止。“
但是,以下出现以释放至少部分内存: 警告:我测量空闲内存的方法是特定于Linux的:
import time
import numpy as np
def free_memory():
"""
Return free memory available, including buffer and cached memory
"""
total = 0
with open('/proc/meminfo', 'r') as f:
for line in f:
line = line.strip()
if any(line.startswith(field) for field in ('MemFree', 'Buffers', 'Cached')):
field, amount, unit = line.split()
amount = int(amount)
if unit != 'kB':
raise ValueError(
'Unknown unit {u!r} in /proc/meminfo'.format(u=unit))
total += amount
return total
def gen_change_in_memory():
"""
https://stackoverflow.com/a/14446011/190597 (unutbu)
"""
f = free_memory()
diff = 0
while True:
yield diff
f2 = free_memory()
diff = f - f2
f = f2
change_in_memory = gen_change_in_memory().next
在分配大数组之前:
print(change_in_memory())
# 0
a = np.zeros(500000)
a[10:20:2] = 1
b = c = a[10:40:4]
分配大数组后:
print(change_in_memory())
# 3844 # KiB
a[:len(b)] = b
b = a[:len(b)]
a.resize(len(b), refcheck=0)
time.sleep(1)
调整大小后可用内存增加:
print(change_in_memory())
# -3708 # KiB
答案 1 :(得分:3)
您可以在cython中执行此操作:
In [1]:
%load_ext cythonmagic
In [2]:
%%cython
cimport numpy as np
np.import_array()
def to_c_contiguous(np.ndarray a):
cdef np.ndarray new
cdef int dim, i
new = a.copy()
dim = np.PyArray_NDIM(new)
for i in range(dim):
np.PyArray_STRIDES(a)[i] = np.PyArray_STRIDES(new)[i]
a.data = new.data
np.PyArray_UpdateFlags(a, np.NPY_C_CONTIGUOUS)
np.set_array_base(a, new)
In [8]:
import sys
import numpy as np
a = np.random.rand(10, 10, 10)
b = c = a[::2, 1::3, 2::4]
d = a[::2, 1::3, 2::4]
print sys.getrefcount(a)
to_c_contiguous(b)
print sys.getrefcount(a)
print np.all(b==d)
输出结果为:
4
3
True
to_c_contiguous(a)
将创建a
的c_contiguous副本,并将其作为a
的基础。
在调用to_c_contiguous(b)
之后,a的引用次数减少,当a的引用次数变为0时,它将被释放。
答案 2 :(得分:1)
我会声称通过np.copy
创建的切片来完成列出的2件事的正确方法。
当然,为了使其正常工作,您需要定义适当的__array_finalize__
。你不是很清楚为什么你决定首先避免它,但我的感觉是你应该定义它。 (如何在不使用bx**2
的情况下解决__array_finalize__
问题?)