当前位置: 首页 > 面试题库 >

Python切片分配内存使用情况

宫瀚
2023-03-14
问题内容

我在此处的注释中读到,更改列表时执行切片分配具有更高的内存效率。例如,

a[:] = [i + 6 for i in a]

应该比

a = [i + 6 for i in a]

因为前者会替换现有列表中的元素,而后者会创建一个新列表并重新绑定a到该新列表,从而将旧列表保留a在内存中,直到可以对其进行垃圾回收为止。对两者进行基准测试以提高速度,后者则要快一些:

$ python -mtimeit -s 'a = [1, 2, 3]' 'a[:] = [i + 6 for i in a]'
1000000 loops, best of 3: 1.53 usec per loop
$ python -mtimeit -s 'a = [1, 2, 3]' 'a = [i + 6 for i in a]'
1000000 loops, best of 3: 1.37 usec per loop

这就是我所期望的,因为重新绑定变量应该比替换列表中的元素更快。但是,我找不到任何支持内存使用声明的官方文档,也不确定如何进行基准测试。

从表面上看,内存使用声明对我来说很有意义。但是,请多加考虑,我希望在前一种方法中,解释器将从列表理解中创建一个新列表, 然后
将该列表中的值复制到a,从而使匿名列表一直浮动直到被垃圾回收为止。 。如果真是这样,那么前一种方法将使用相同数量的内存,同时速度也会变慢。

谁能(用基准或官方文档)明确显示这两种方法中哪一种更有效地使用内存/哪一种是首选方法?

提前致谢。


问题答案:

线

a[:] = [i + 6 for i in a]

不会节省任何内存。如语言文档中所述,Python会首先评估右侧:

赋值语句评估表达式列表(请记住,它可以是单个表达式或逗号分隔的列表,后者产生一个元组),并将单个结果对象从左到右分配给每个目标列表。

在当前情况下,单个结果对象将是一个新列表,而目标列表中的单个目标将是a[:]

我们可以用生成器表达式代替列表推导:

a[:] = (i + 6 for i in a)

现在,右侧将求值为生成器,而不是列表。基准测试表明,这仍然比天真慢

a = [i + 6 for i in a]

那么生成器表达式实际上可以节省任何内存吗?乍一看,您可能会认为确实如此。但是深入研究该函数list_ass_slice()的源代码表明事实并非如此。线

v_as_SF = PySequence_Fast(v, "can only assign an iterable");

使用PySequence_Fast()首先将可迭代对象(在这种情况下为生成器)转换为元组,然后将其复制到旧列表中。元组使用与列表相同的内存量,因此在这种情况下,使用生成器表达式与使用列表推导基本上相同。在最后一次复制期间,原始列表的项目被重用。

道德似乎是,无论如何,最简单的方法都是最好的方法。



 类似资料:
  • 问题内容: 我知道Valgrind,但它只是检测内存管理问题。我要搜索的是一个概述的工具,程序的哪些部分确实消耗了多少内存。带有树形图的图形表示(就像KCachegrind对Callgrind所做的那样)会很酷。 我在Linux机器上工作,所以Windows工具对我没有太大帮助。 问题答案: 使用massif,这是Valgrind工具的一部分。massif- visualizer 可以帮助您绘制数

  • 问题内容: 我写了一个程序,可以总结如下: 实际代码(尤其是)要复杂得多。仅使用将其当作参数的这些值(意味着它不引用) 基本上,它将巨大的数据集加载到内存中并进行处理。输出的写操作委托给一个子进程(它实际上写到多个文件中,这需要很多时间)。因此,每次处理一个数据项时,它都会通过res_queue发送到子流程,然后该子流程根据需要将结果写入文件中。 子流程不需要访问,读取或修改以任何方式加载的数据。

  • 我想了解为什么多次动态分配调用的数据比直接在代码中指定的或通过的单个调用分配的数据使用如此多的内存。 例如,我用C编写了以下两个代码: 测试1.c:int x用malloc分配 我在这里没有使用free来保持简单。当程序等待交互时,我查看另一个终端中的顶级功能,它向我显示了以下内容: test2. c: int x不是动态分配的 顶部显示: 我还编写了第三个代码,其结果与test2相同,我在tes

  • 我使用5.6.21-70.0进行性能测试。 当我跑步时 mysqlslp-a--并发=40--查询次数1000次--迭代=500次--引擎=innodb--debug-info-utest-p 做一些性能测试,ram增长超过最大内存使用量,永不释放 当完成mysqlslap时,内存显示使用78% 我有1G物理内存,不使用交换 KiB Mem:总共1016656个,使用953808个,免费62848

  • 问题内容: 我需要从数组中的多个位置提取数据。 一个简单的数组是: 我对切片很熟悉。例如:- 会给我:- 但是,我无法摆脱多个层面。例如:- 给我 尽管搜索了两本Python书籍和Internet,但我无法确定要使用的语法。 问题答案: 您可以切片两次并加入它们。

  • 问题内容: 是否有一个准则来估计a消耗的内存量? 寻找类似于这些准则的估计内存使用情况的东西。 问题答案: 如果您查看源代码中的字段,则有: 的评论说 用于存储规范的字符串表示形式(如果已计算)。 假设您不调用,它将保留为零字节。因此是(8 + 4 + 4)= 16个字节+ 。 本身是4 + 4 + 4 + 4 + 4 = 20字节+ 。 20 + 16总共提供了36个字节加上大小,该大小始终是表