递归切片numpy数组是否会产生惩罚?

5

假设我想要将一个 np 数组作为固定的只读队列并将其前端弹出。以下是一种自然的实现方式:

def pop(k,q):
    return q[:k],q[k:]
## example usage:
x = np.arange(1000)
for i in range(5):
    a,x = pop(i,x)
    print(a) 

这看起来还不错,但我想确保如果 q=q[k:] 执行了数千次或数百万次,没有隐藏状态或隐藏引用会逐渐累积。似乎没有:为了取一个切片,np只是简单地存储原始数据缓冲区的指针和新索引。 但我想确定一下,因为如果有我遗漏的东西,我可以将其表示为一个元组 (np.array, index) ,但这并不够简洁:

def pop0(k,q):
    x,i = q
    return x[i:i+k],(x,i+k)
1个回答

1

这是安全的。您可以使用memory-profiler包观察内存使用情况:

对于以下代码:

import numpy as np

@profile
def good_pop():
    def pop(k,q):
        return q[:k],q[k:]
    x = np.arange(10000)
    for i in range(5000):
        a,x = pop(i,x)

@profile
def bad_pop():
    def pop(k,q):
        return q[:k].copy(),q[k:].copy()
    x = np.arange(10000)
    for i in range(5000):
        a,x = pop(i,x)

good_pop()
bad_pop()

使用命令进行性能分析:
$ python3 -m memory_profiler file.py

产生的结果:
Line #    Mem usage    Increment   Line Contents
================================================
     3   49.023 MiB   49.023 MiB   @profile
     4                             def good_pop():
     5   49.023 MiB    0.000 MiB       def pop(k,q):
     6   49.023 MiB    0.000 MiB           return q[:k],q[k:]
     7   49.023 MiB    0.000 MiB       x = np.arange(10000)
     8   49.023 MiB    0.000 MiB       for i in range(5000):
     9   49.023 MiB    0.000 MiB           a,x = pop(i,x)


Line #    Mem usage    Increment   Line Contents
================================================
    11   49.023 MiB   49.023 MiB   @profile
    12                             def bad_pop():
    13   49.234 MiB    0.000 MiB       def pop(k,q):
    14   49.234 MiB    0.211 MiB           return q[:k].copy(),q[k:].copy()
    15   49.023 MiB    0.000 MiB       x = np.arange(10000)
    16   49.234 MiB    0.000 MiB       for i in range(5000):
    17   49.234 MiB    0.000 MiB           a,x = pop(i,x)
< p >对于good_pop()的一堆零证明在这个循环中没有创建额外的对象。


1
或者说创建的对象小于1 kiB,因此可以忽略不计。 - Guimoute

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接