关于读写文件执行速度 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Virace
V2EX    Python

关于读写文件执行速度

  •  
  •   Virace 2021-04-14 21:01:56 +08:00 2215 次点击
    这是一个创建于 1716 天前的主题,其中的信息可能已经有所发展或是发生改变。
    代码不好贴, 因为涉及到很多个文件

    简单就是:
    读取 A 类 文件, 根据偏移量提取出 B 类文件, 解析 B 类文件中的数据.

    A 类文件中有可能有多个 B 类文件.
    A 类文件几十兆, B 类文件几兆.
    B 类文件是不写入本地的, 直接解析.



    大概有接近 1000 个 A 类文件, 随着循环时间越来越长, 解析 B 类文件数据的这个函数执行会越来越慢.
    多数使用过的变量 都有手动用 del 删除


    每次循环 A 文件前 关闭 gc, A 文件使用后开启 gc 手动调用 gc.collect()

    随着循环次数变多, 解析 B 类文件的函数, 就会从最开始的几十毫秒到后来的几秒甚至时间更长.

    占用内存波动不大, 一直是 300M 左右
    第 1 条附言    2021-04-14 22:59:40 +08:00

    用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 

    这个函数是 解析用 模块中的函数

    26 条回复    2021-04-20 10:19:18 +08:00
    imn1
        1
    imn1  
       2021-04-14 21:14:17 +08:00
    那就加大内存使用量,A 全部读入内存后关闭
    Virace
        2
    Virace  
    OP
       2021-04-14 21:19:46 +08:00
    @imn1 还是内存的事么, 测试机内存倒是够用, 实际是要在一个 运行内存只有 1G 的机器上运行. = =
    F281M6Dh8DXpD1g2
        3
    F281M6Dh8DXpD1g2  
       2021-04-14 21:26:04 +08:00 via iPhone
    解析完了记下来不就完了
    abersheeran
        4
    abersheeran  
       2021-04-14 21:29:06 +08:00
    根据偏移量直接读文件某一部分这事可以先上 mmap 优化一下看看。另外你这个确定是慢在解析上吗?是不是内存超限了导致系统自动分配虚拟内存给你,疯狂交换虚拟内存页导致的。我以前遇到过类似问题。你可以先排查一下。
    westoy
        5
    westoy  
       2021-04-14 21:30:22 +08:00
    不要管程序吃多少内存

    跑的时候观察下吃 swap 没有

    你不停做文件读写, 等于不停触发 linux 的文件缓存机制,linux 也不是彻底没内存才会触发 swap

    swap 占用不停变化的话, 直接禁用或者调整内核的 vm.swapiness
    Virace
        6
    Virace  
    OP
       2021-04-14 21:38:44 +08:00
    @abersheeran 对只是慢在解析上, 简单的装饰器计算运行时间的. 测试是在 win 环境下出现的.
    clino
        7
    clino  
       2021-04-14 21:39:22 +08:00
    "随着循环次数变多, 解析 B 类文件的函数, 就会从最开始的几十毫秒到后来的几秒甚至时间更长."
    是解析本身的耗时越来越长吗?不太理解这是什么导致的。
    Virace
        8
    Virace  
    OP
       2021-04-14 21:39:55 +08:00
    @westoy 测试是在 win 环境下出现的. 也会有类似的情况嘛.
    abersheeran
        9
    abersheeran  
       2021-04-14 21:42:34 +08:00
    @Virace Windows 也有虚拟内存的。先排查这个情况再考虑其他的。任何语言都不会因为整个程序的内存占用变多而运算变慢的。出现这情况大概率是虚拟内存的锅。
    geelaw
        10
    geelaw  
       2021-04-14 21:44:30 +08:00 via iPhone
    为什么你要关掉 GC ?
    Virace
        11
    Virace  
    OP
       2021-04-14 21:52:50 +08:00
    @geelaw 经过测试在读入文件后 关闭 GC 执行后续操作 操作完毕在打开 GC 手动清理, 比平常要快. 意思就是如果不关闭的话, 这种越运行越慢的问题会更严重
    crclz
        12
    crclz  
       2021-04-14 22:06:44 +08:00
    建议楼主把代码贴出来,给大家一个最小的可重现的代码,既方便大家调试,也方便排除其他问题。
    还有就是楼主一些地方的表述不太清晰,可能会让项目成员以外的路人产生困惑。例如“随着循环时间越来越长, 解析 B 类文件数据的这个函数执行会越来越慢”
    crclz
        13
    crclz  
       2021-04-14 22:07:53 +08:00
    还有一个建议:用某种 profiler 看看到底哪些函数是罪魁祸首,方便定位问题
    Virace
        14
    Virace  
    OP
       2021-04-14 22:18:19 +08:00
    代码不好贴, 解析的意思, B 类文件是个独有个格式, 经过几个循环能完全读完. 将读完的数据保存到本地. 这是这个解析函数要做的. 确实用 pycharm 的 profiler 运行了一下, 显示 76%的时间都在这个解析函数上.
    keakon
        15
    keakon  
       2021-04-14 22:32:50 +08:00
    如果解析的文件是 json 的话,市面上所有的 json 库都会内存泄露
    Virace
        16
    Virace  
    OP
       2021-04-14 22:35:58 +08:00
    @keakon 解析倒不是, 解析完毕保存的数据是 json.
    clino
        17
    clino  
       2021-04-14 22:44:44 +08:00
    你说解析函数有误导性,看起来其实这个函数不光做了解析还干了很多其他的事情,这里面有很多细节和可能性。
    我的建议是仔细研究这个函数,看到底越来越慢是这个函数的哪一步导致的,如果能找到,那大概率能猜出是什么导致越来越慢。
    xiaoming1992
        18
    xiaoming1992  
       2021-04-14 22:54:18 +08:00
    笨办法,把那个解析函数按照二分法,移除掉一部分功能后再运行试试
    Virace
        19
    Virace  
    OP
       2021-04-14 23:00:41 +08:00
    @clino 用 profiler 工具找出了一个运行比较长的函数, 已经贴到附言上了
    wuwukai007
        20
    wuwukai007  
       2021-04-14 23:42:51 +08:00
    要不用 pysnooper 逐行分析一下?
    gBurnX
        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

    注意一下函数执行速度,与 内存使用率 / 磁盘活动时间的关系。
    clino
        22
    clino  
       2021-04-15 11:48:49 +08:00
    从 obj_find_one 的实现来看,应该是这个遍历耗时很长,看能否调整数据结构,让这个查询不需要遍历,或者看能否做预处理形成一个中间数据结构让查询不需要遍历。

    gc.collect 的优化看看能不能不要每次都做,还有 gc.collect 的参数你看能不能给 0 试试 gc 效果如何。
    Virace
        23
    Virace  
    OP
       2021-04-15 17:53:37 +08:00
    @clino 去掉这个函数了, 改用字典了, 时间缩短不少. 但开始运行和运行一段时间后性能还是有差别. 目前从 profiler 工具给的信息看, 大部分时间除了几个循环就是 GC 了.
    clino
        24
    clino  
       2021-04-16 09:55:09 +08:00
    gc.collect 的参数调整没用吗?
    另外不做 gc 的后果是什么?内存暴涨?能否重用 dict 之类的对象来减少新对象的创建?还有就是检测一下内存用量,超过临界值了再执行 gc 。
    Virace
        25
    Virace  
    OP
       2021-04-19 22:20:37 +08:00
    @clino 同等情况下手动执行 gc 和自动 gc 占用内存是有区别的, 比如 100 个 A 类文件循环处理时不调用 GC 可能最高内存会超过 1G, 手动调用最高也只在 400M 左右. 但是不管手动调用还是自动, 这个 gc 在整个程序执行时间时间里是得占用个 30 左右. 好多情况得需要额外复制对象在进行处理, 因为原对象后续还需要使用.
    clino
        26
    clino  
       2021-04-20 10:19:18 +08:00
    或者你实在优化有问题,考虑把对象内的数据外包给 redis 处理,这样 python 这里只要做数据查询就可以了,不用面临这种 python 内部内存暴涨的情况
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2697 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 11:46 PVG 19:46 LAX 03:46 JFK 06:46
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86