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中的greenlet包实现并发编程的入门教程
Apr 16 Python
Python实现的简单算术游戏实例
May 26 Python
python获取局域网占带宽最大3个ip的方法
Jul 09 Python
python检查字符串是否是正确ISBN的方法
Jul 11 Python
Python使用OpenCV进行标定
May 08 Python
Python爬取成语接龙类网站
Oct 19 Python
Python实现将多个空格换为一个空格.md的方法
Dec 20 Python
Python逐行读取文件中内容的简单方法
Feb 26 Python
Python实现的爬取小说爬虫功能示例
Mar 30 Python
树莓派极简安装OpenCv的方法步骤
Oct 10 Python
python 使用cx-freeze打包程序的实现
Mar 14 Python
详解使用Python写一个向数据库填充数据的小工具(推荐)
Sep 11 Python
python基于机器学习预测股票交易信号
Python数据可视化之绘制柱状图和条形图
总结Python常用的魔法方法
Python入门学习之类的相关知识总结
python munch库的使用解析
May 25 #Python
python调试工具Birdseye的使用教程
浅谈Python numpy创建空数组的问题
May 25 #Python
You might like
PHP 日常开发小技巧
2009/09/23 PHP
PHP统计nginx访问日志中的搜索引擎抓取404链接页面路径
2014/06/30 PHP
Windows下安装PHP单元测试环境PHPUnit图文教程
2014/10/24 PHP
PHP反射机制原理与用法详解
2017/02/15 PHP
PHP中通过getopt解析GNU C风格命令行选项
2019/11/18 PHP
jquery photoFrame 图片边框美化显示插件
2010/06/28 Javascript
浅谈nodeName,nodeValue,nodeType,typeof 的区别
2015/01/13 Javascript
ECMAScript6中Set/WeakSet详解
2015/06/12 Javascript
javascript页面倒计时实例
2015/07/25 Javascript
深入了解JavaScript中的Symbol的使用方法
2015/07/28 Javascript
JavaScript设置、获取、清除单值和多值cookie的方法
2015/11/17 Javascript
关于微信上网页图片点击全屏放大效果
2016/12/19 Javascript
jQuery 插件实现随机自由弹跳气泡样式
2017/01/12 Javascript
iframe与主框架跨域相互访问实现方法
2017/09/14 Javascript
你应该知道的几类npm依赖包管理详解
2017/10/06 Javascript
nodejs的路径问题的解决
2018/06/30 NodeJs
使用ng-packagr打包Angular的方法示例
2018/09/21 Javascript
JavaScript实现简单轮播图效果
2018/12/01 Javascript
详解element-ui级联菜单(城市三级联动菜单)和回显问题
2019/10/02 Javascript
Vue搭建后台系统需要注意的问题
2019/11/08 Javascript
全面解析js中的原型,原型对象,原型链
2021/01/25 Javascript
python通过定义一个类实例作为ftp回调方法
2015/05/04 Python
python开发中range()函数用法实例分析
2015/11/12 Python
python实现从文件中读取数据并绘制成 x y 轴图形的方法
2018/10/14 Python
python 自定义对象的打印方法
2019/01/12 Python
python使用pip安装模块出现ReadTimeoutError: HTTPSConnectionPool的解决方法
2019/10/04 Python
Django+uni-app实现数据通信中的请求跨域的示例代码
2019/10/12 Python
如何基于Python爬虫爬取美团酒店信息
2020/11/03 Python
HTML5 本地存储和内容按需加载的思路和方法
2011/04/07 HTML / CSS
简单说下OSPF的操作过程
2014/08/13 面试题
护理自荐信
2013/10/22 职场文书
建筑班组长岗位职责
2014/01/02 职场文书
求职信范文英文版
2014/01/05 职场文书
新郎婚宴答谢词
2014/01/19 职场文书
七年级之开学家长寄语35句
2019/09/05 职场文书
Win11控制面板快捷键是什么?Win11打开控制面板的方法汇总
2022/07/07 数码科技