用pycharm的profiler工具分析了一下, 时间用在GC和一个函数中.
def obj_find_one(obj, key, value):
"""
查询对象数组中key属性等于value的对象
:param obj: 对象数组
:param key: 对象属性名
:param value: 要查找的属性值
:return:
"""
for item in obj:
if getattr(item, key) == value:
return item
这个函数是 解析用 模块中的函数
1
imn1 2021-04-14 21:14:17 +08:00
那就加大内存使用量,A 全部读入内存后关闭
|
3
liprais 2021-04-14 21:26:04 +08:00 via iPhone
解析完了记下来不就完了
|
4
abersheeran 2021-04-14 21:29:06 +08:00
根据偏移量直接读文件某一部分这事可以先上 mmap 优化一下看看。另外你这个确定是慢在解析上吗?是不是内存超限了导致系统自动分配虚拟内存给你,疯狂交换虚拟内存页导致的。我以前遇到过类似问题。你可以先排查一下。
|
5
westoy 2021-04-14 21:30:22 +08:00
不要管程序吃多少内存
跑的时候观察下吃 swap 没有 你不停做文件读写, 等于不停触发 linux 的文件缓存机制,linux 也不是彻底没内存才会触发 swap swap 占用不停变化的话, 直接禁用或者调整内核的 vm.swapiness |
6
Virace OP @abersheeran 对只是慢在解析上, 简单的装饰器计算运行时间的. 测试是在 win 环境下出现的.
|
7
clino 2021-04-14 21:39:22 +08:00
"随着循环次数变多, 解析 B 类文件的函数, 就会从最开始的几十毫秒到后来的几秒甚至时间更长."
是解析本身的耗时越来越长吗?不太理解这是什么导致的。 |
9
abersheeran 2021-04-14 21:42:34 +08:00
@Virace Windows 也有虚拟内存的。先排查这个情况再考虑其他的。任何语言都不会因为整个程序的内存占用变多而运算变慢的。出现这情况大概率是虚拟内存的锅。
|
10
geelaw 2021-04-14 21:44:30 +08:00 via iPhone
为什么你要关掉 GC ?
|
11
Virace OP @geelaw 经过测试在读入文件后 关闭 GC 执行后续操作 操作完毕在打开 GC 手动清理, 比平常要快. 意思就是如果不关闭的话, 这种越运行越慢的问题会更严重
|
12
crclz 2021-04-14 22:06:44 +08:00
建议楼主把代码贴出来,给大家一个最小的可重现的代码,既方便大家调试,也方便排除其他问题。
还有就是楼主一些地方的表述不太清晰,可能会让项目成员以外的路人产生困惑。例如“随着循环时间越来越长, 解析 B 类文件数据的这个函数执行会越来越慢” |
13
crclz 2021-04-14 22:07:53 +08:00
还有一个建议:用某种 profiler 看看到底哪些函数是罪魁祸首,方便定位问题
|
14
Virace OP 代码不好贴, 解析的意思, B 类文件是个独有个格式, 经过几个循环能完全读完. 将读完的数据保存到本地. 这是这个解析函数要做的. 确实用 pycharm 的 profiler 运行了一下, 显示 76%的时间都在这个解析函数上.
|
15
keakon 2021-04-14 22:32:50 +08:00
如果解析的文件是 json 的话,市面上所有的 json 库都会内存泄露
|
17
clino 2021-04-14 22:44:44 +08:00
你说解析函数有误导性,看起来其实这个函数不光做了解析还干了很多其他的事情,这里面有很多细节和可能性。
我的建议是仔细研究这个函数,看到底越来越慢是这个函数的哪一步导致的,如果能找到,那大概率能猜出是什么导致越来越慢。 |
18
xiaoming1992 2021-04-14 22:54:18 +08:00
笨办法,把那个解析函数按照二分法,移除掉一部分功能后再运行试试
|
20
wuwukai007 2021-04-14 23:42:51 +08:00
要不用 pysnooper 逐行分析一下?
|
21
gBurnX 2021-04-15 00:24:00 +08:00
watch -n 1 'free -h'
htop -d 1 dstat -t -n -d -c -g -i -l -m -p -s -y --ipc --lock --raw --tcp --udp --unix iostat -x -m -d 1 注意一下函数执行速度,与 内存使用率 / 磁盘活动时间的关系。 |
22
clino 2021-04-15 11:48:49 +08:00
从 obj_find_one 的实现来看,应该是这个遍历耗时很长,看能否调整数据结构,让这个查询不需要遍历,或者看能否做预处理形成一个中间数据结构让查询不需要遍历。
gc.collect 的优化看看能不能不要每次都做,还有 gc.collect 的参数你看能不能给 0 试试 gc 效果如何。 |
23
Virace OP @clino 去掉这个函数了, 改用字典了, 时间缩短不少. 但开始运行和运行一段时间后性能还是有差别. 目前从 profiler 工具给的信息看, 大部分时间除了几个循环就是 GC 了.
|
24
clino 2021-04-16 09:55:09 +08:00
gc.collect 的参数调整没用吗?
另外不做 gc 的后果是什么?内存暴涨?能否重用 dict 之类的对象来减少新对象的创建?还有就是检测一下内存用量,超过临界值了再执行 gc 。 |
25
Virace OP @clino 同等情况下手动执行 gc 和自动 gc 占用内存是有区别的, 比如 100 个 A 类文件循环处理时不调用 GC 可能最高内存会超过 1G, 手动调用最高也只在 400M 左右. 但是不管手动调用还是自动, 这个 gc 在整个程序执行时间时间里是得占用个 30 左右. 好多情况得需要额外复制对象在进行处理, 因为原对象后续还需要使用.
|
26
clino 2021-04-20 10:19:18 +08:00
或者你实在优化有问题,考虑把对象内的数据外包给 redis 处理,这样 python 这里只要做数据查询就可以了,不用面临这种 python 内部内存暴涨的情况
|