Python 循环读取数据内存不足的解决方案


Posted in Python onMay 25, 2021

看代码吧~

import gc
for x in list(locals().keys())[:]:
    del locals()[x]
# del all_s_x, AE, AE_split, x_ticks, split
gc.collect()

补充:Python读取大文件的"坑“与内存占用检测

python读写文件的api都很简单,一不留神就容易踩”坑“。笔者记录一次踩坑历程,并且给了一些总结,希望到大家在使用python的过程之中,能够避免一些可能产生隐患的代码。

1.read()与readlines():

随手搜索python读写文件的教程,很经常看到read()与readlines()这对函数。所以我们会常常看到如下代码:

with open(file_path, 'rb') as f:
    sha1Obj.update(f.read())

or

with open(file_path, 'rb') as f:
    for line in f.readlines():
        print(line)

这对方法在读取小文件时确实不会产生什么异常,但是一旦读取大文件,很容易会产生MemoryError,也就是内存溢出的问题。

Why Memory Error?

我们首先来看看这两个方法:

当默认参数size=-1时,read方法会读取直到EOF,当文件大小大于可用内存时,自然会发生内存溢出的错误。

Python 循环读取数据内存不足的解决方案

同样的,readlines会构造一个list。list而不是iter,所以所有的内容都会保存在内存之上,同样也会发生内存溢出的错误。

Python 循环读取数据内存不足的解决方案

2.正确的用法:

在实际运行的系统之中如果写出上述代码是十分危险的,这种”坑“十分隐蔽。所以接下来我们来了解一下正确用,正确的用法也很简单,依照API之中对函数的描述来进行对应的编码就OK了:

如果是二进制文件推荐用如下这种写法,可以自己指定缓冲区有多少byte。显然缓冲区越大,读取速度越快。

with open(file_path, 'rb') as f:
    while True:
        buf = f.read(1024)
        if buf:    
            sha1Obj.update(buf)
        else:
            break

而如果是文本文件,则可以用readline方法或直接迭代文件(python这里封装了一个语法糖,二者的内生逻辑一致,不过显然迭代文件的写法更pythonic )每次读取一行,效率是比较低的。笔者简单测试了一下,在3G文件之下,大概性能和前者差了20%.

with open(file_path, 'rb') as f:
    while True:
        line = f.readline()
        if buf:    
            print(line)
        else:
            break
with open(file_path, 'rb') as f:
    for line in f:
        print(line)

3.内存检测工具的介绍:

对于python代码的内存占用问题,对于代码进行内存监控十分必要。这里笔者这里推荐两个小工具来检测python代码的内存占用。

memory_profiler

首先先用pip安装memory_profiler

pip install memory_profiler

memory_profiler是利用python的装饰器工作的,所以我们需要在进行测试的函数上添加装饰器。

from hashlib import sha1
import sys
@profile
def my_func():
    sha1Obj = sha1()
    with open(sys.argv[1], 'rb') as f:
        while True:
            buf = f.read(10 * 1024 * 1024)
            if buf:
                sha1Obj.update(buf)
            else:
                break
    print(sha1Obj.hexdigest())
if __name__ == '__main__':
    my_func()

之后在运行代码时加上** -m memory_profiler**

就可以了解函数每一步代码的内存占用了

Python 循环读取数据内存不足的解决方案

guppy

依样画葫芦,仍然是通过pip先安装guppy

pip install guppy

之后可以在代码之中利用guppy直接打印出对应各种python类型(list、tuple、dict等)分别创建了多少对象,占用了多少内存。

from guppy import hpy
import sys
def my_func():
    mem = hpy()
    with open(sys.argv[1], 'rb') as f:
        while True:
            buf = f.read(10 * 1024 * 1024)
            if buf:
                print(mem.heap())
            else:
                break

如下图所示,可以看到打印出对应的内存占用数据:

Python 循环读取数据内存不足的解决方案

通过上述两种工具guppy与memory_profiler可以很好地来监控python代码运行时的内存占用问题。

4.小结:

python是一门崇尚简洁的语言,但是正是因为它的简洁反而更多了许多需要仔细推敲和思考的细节。希望大家在日常工作与学习之中也能多对一些细节进行总结,少踩一些不必要的“坑”。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
跟老齐学Python之编写类之三子类
Oct 11 Python
python制作websocket服务器实例分享
Nov 20 Python
Python科学计算之Pandas详解
Jan 15 Python
python中将一个全部为int的list 转化为str的list方法
Apr 09 Python
解决Pycharm中import时无法识别自己写的程序方法
May 18 Python
python实现字符串加密 生成唯一固定长度字符串
Mar 22 Python
python3下载抖音视频的完整代码
Jun 05 Python
将python运行结果保存至本地文件中的示例讲解
Jul 11 Python
django框架forms组件用法实例详解
Dec 10 Python
Pytorch .pth权重文件的使用解析
Feb 14 Python
python 实现性别识别
Nov 21 Python
python 利用jieba.analyse进行 关键词提取
Dec 17 Python
python基于机器学习预测股票交易信号
Python数据可视化之绘制柱状图和条形图
总结Python常用的魔法方法
Python入门学习之类的相关知识总结
python munch库的使用解析
May 25 #Python
python调试工具Birdseye的使用教程
浅谈Python numpy创建空数组的问题
May 25 #Python
You might like
利用PHP和AJAX创建RSS聚合器的代码
2007/03/13 PHP
php 字符串函数收集
2010/03/29 PHP
浅析ThinkPHP中execute和query方法的区别
2014/06/13 PHP
php格式化时间戳显示友好的时间实现思路及代码
2014/10/23 PHP
php中引用&的用法分析【变量引用,函数引用,对象引用】
2016/12/12 PHP
bindParam和bindValue的区别以及在Yii2中的使用详解
2018/03/12 PHP
php实现推荐功能的简单实例
2019/09/29 PHP
php+mysql+ajax 局部刷新点赞/取消点赞功能(每个账号只点赞一次)
2020/07/24 PHP
javascript延时重复执行函数 lLoopRun.js
2007/06/29 Javascript
javascript 写类方式之四
2009/07/05 Javascript
JQuery AJAX提交中文乱码的解决方案
2010/07/02 Javascript
JavaScript中的isXX系列是否继续使用的分析
2011/04/16 Javascript
Jquery实现带动画效果的经典二级导航菜单
2013/03/22 Javascript
在页面上用action传递参数到后台出现乱码的解决方法
2013/12/31 Javascript
javascript给span标签赋值的方法
2015/11/26 Javascript
javascript每日必学之封装
2016/02/23 Javascript
打造自己的jQuery插件入门教程
2016/09/23 Javascript
JS中from 表单序列化提交的代码
2017/01/20 Javascript
jQuery插件HighCharts绘制的基本折线图效果示例【附demo源码下载】
2017/03/07 Javascript
jQuery插件HighCharts绘制的2D堆柱状图效果示例【附demo源码下载】
2017/03/14 Javascript
基于Vue2的独立构建与运行时构建的差别(详解)
2017/12/06 Javascript
vue 使用自定义指令实现表单校验的方法
2018/08/28 Javascript
js实现下拉框二级联动
2018/12/04 Javascript
python使用7z解压软件备份文件脚本分享
2014/02/21 Python
Python任务自动化工具tox使用教程
2020/03/17 Python
CSS中垂直居中的简单实现方法
2015/07/06 HTML / CSS
从当地商店送来的杂货:Instacart
2018/08/19 全球购物
速比涛英国官网:Speedo英国
2019/07/15 全球购物
西班牙在线宠物食品和配件商店:bitiba
2019/10/11 全球购物
英国运动服、设备及配件网站:DW Sports
2019/12/04 全球购物
局域网标准
2016/09/10 面试题
办公设备采购方案
2014/03/16 职场文书
社会发展项目建议书
2014/08/25 职场文书
python中sys模块的介绍与实例
2021/04/17 Python
vue.js 使用原生js实现轮播图
2022/04/26 Vue.js
win10怎么设置右下角图标不折叠?Win10设置右下角图标不折叠的方法
2022/07/15 数码科技