【发布时间】:2022-08-03 10:32:59
【问题描述】:
UPD:解决了几个问题。
我们有四个文件实现,文件中有 10**7 个整数(一个数字 - 一行)。
| Case | Code. Parameter int=int for non-using global scope |
|---|---|
| map |
def without_readlines(int=int): data = list(map(int, open(\'test.txt\')))
|
| map + readlines |
def with_readlines(int=int): data = list(map(int, open(\'test.txt\').readlines()))
|
| list comprehension |
def without_readlines_listcomp(int=int): data = [int(x) for x in open(\'test.txt\')]
|
| list comprehension + readlines |
def with_readlines_listcomp(int=int): data = [int(x) for x in open(\'test.txt\').readlines()]
|
速度测试的第一个问题:
功能测试的代码类似。
from timeit import default_timer
def func():
pass
if __name__ == \'__main__\':
st = default_timer()
func()
print(default_timer() - st)
| without_readlines() | with_readlines() | without_readlines_listcomp() | with_readlines_listcomp() |
|---|---|---|---|
| 1.51-1.56 sec | 1.6-1.8 sec | 1.79-1.82 sec | 1.89-1.93 sec |
1)为什么列表比较变体和地图变体之间的差异是 2-3 倍? 0.2-0.3 与 0.07-0.12
内存分析的第二个问题。
功能测试的代码类似。
UPD:此方法不显示 map 函数的深度内存使用情况。
from memory_profiler import profile
@profile
def func():
pass
if __name__ == \'__main__\':
func()
| Mem usage | Increment | Occurences | Line Contents | |
|---|---|---|---|---|
| without_readlines | 19.3 MiB 406.0 MiB |
19.3 MiB 386.7 MiB |
1 1 |
@profile def without_readlines(int=int): data = list(map(int, open(\'test.txt\'))) |
| with_readlines | 19.4 MiB 402.4 MiB |
19.4 MiB 383.0 MiB |
1 1 |
@profile def with_readlines(int=int): data = list(map(int, open(\'test.txt\').readlines())) |
| without_readlines listcomp |
19.4 MiB 402.5 MiB |
19.4 MiB -24068.2 MiB |
1 10000003 |
@profile def without_readlines_listcomp(int=int): data = list(map(int, open(\'test.txt\'))) |
| with_readlines listcomp |
19.4 MiB 1092.4 MiB |
19.4 MiB -4585.2 MiB |
1 10000003 |
@profile def with_readlines_listcomp(int=int): data = list(map(int, open(\'test.txt\').readlines())) |
2)为什么 listcomp 变体之间的差异大于 600 MiB?它的内存可以存储 10**7 个字符串吗?
回答:是的,它是 10**7 个字符串的对象大小(列表大小 + 此列表中所有字符串的大小)。
from sys import getsizeof
strs = open(\'test.txt\').readlines()
print(getsizeof(strs) + sum(map(getsizeof, strs)))
# 657 984 050
3)为什么地图变体之间的差异小于 85 MiB? 85 MiB - 包含 10**7 个字符串的列表大小。
回答:差异 86 MiB 是带有字符串的列表对象的大小(file.readlines() 的结果)。不列出+所有字符串。仅列出对象。
from sys import getsizeof
print(getsizeof(open(\'test.txt\').readlines()))
# 89 095 160
测试差异不正确。在下一个答案中计算 map 函数的内存使用情况的正确方法。
4)地图功能如何在低级别工作?为什么列表理解函数的内存差异不相似?
回答:因为装饰器@profile 没有显示深度调用的内存使用情况。
对于正确的内存测试,我使用下一种方法。
from memory_profiler import profile, memory_usage
start_mem = memory_usage(max_usage=True)
res = memory_usage(proc=(func), max_usage=True, include_children=True, retval=True)
print(res[0] - start_mem)
该测试的结果:
| with_readlines | without_readlines | with_readlines_listcomp | without_readlines_listcomp |
|---|---|---|---|
| 1065-1164 MiB | 402-475 MiB | 1061-1124 MiB | 393-468 MiB |
此类数据与使用 python 对象的逻辑相融合。
5)增量的负值是什么意思?
-
map不返回列表,因此您不会比较相同的事物。并且 \"without listcomp\" 正在使用列表理解 -
对不起,列表(地图())。查了一下这一刻。
标签: python list-comprehension memory-profiling