python读取大数据量文件

python中大数据文件读取 python中经常会遇到读取大文件的场景。文件较小时,我通常采用下面方法,readlines(),该方法会一次性读取文件的所有行,并将其放入list中,最后存入内存中 。可想而知,当文件较大是,内存占用会非常高,

python中大数据文件读取

python中经常会遇到读取大文件的场景。文件较小时,我通常采用下面方法,readlines(),该方法会一次性读取文件的所有行,并将其放入list中,最后存入内存中。可想而知,当文件较大是,内存占用会非常高,甚至造成内存溢出,进程被系统kill掉。

# 读取方式一
with open(file_path, 'r+', encoding='utf-8') as f:
    count = 0
    for line in f.readlines():
        count += 1
    print(count)

运行前:
系统总计内存:8056.3M
系统已经使用内存:6264.3M
系统空闲内存:1791.3M
20465
运行后:
系统总计内存:8056.3M
系统已经使用内存:6266.3M
系统空闲内存:1789.3M

实验采用的文件大小为800k,不算太大,可以看出,占用内存2M

推荐方法:迭代器迭代遍历

python中有个迭代器的概念。迭代,其实就是对序列中的元素进行处理的一种方式

下面我们用可迭代对象进行迭代遍历,测试其占用内存大小。for line in f,会自动使用缓存IO以及内存管理

# 读取方式二
with open(file_path, 'r+', encoding='utf-8') as f:
    count = 0
    for line in f:
        count += 1
    print(count)

运行前:
系统总计内存:8056.3M
系统已经使用内存:5883.3M
系统空闲内存:2172.3M
20465
运行后:
系统总计内存:8056.3M
系统已经使用内存:5884.3M
系统空闲内存:2171.3M

实验采用的文件大小为800k,不算太大,可以看出,占用内存1M,比第一种方法节约内存。

推荐方法:生成器

生成器(Generator)是创建迭代器的简单而强大的工具。写起来就像是正规的函数,只是在返回数据的时候需要使用yield语句。

# 读取方式三
# 生成器函数,用于自定义创建迭代器read_fileline_generator
def read_fileline_generator(file, size=4096):
    while 1:
        data = file.read(size)
        if not data:
            break
        yield data


with open(file_path, 'r+', encoding='utf-8') as f:
    count = 0
    for line in read_fileline_generator(f):
        count += 1

运行前:
系统总计内存:8056.3M
系统已经使用内存:5719.3M
系统空闲内存:2336.3M
运行后:
系统总计内存:8056.3M
系统已经使用内存:5720.3M
系统空闲内存:2335.3M

实验采用的文件大小为800k,不算太大,可以看出,占用内存1M,比第一种方法节约内存。

生成器

上面我们采用生成器创建了一个迭代器对文件进行迭代遍历。那什么是生成器呢?我们来仔细研究下生成器,生成器类似于返回值为数组的一个函数。

为了支持迭代协议,拥有yield语句的函数被编译为生成器,这类函数被调用时返回一个生成器对象,返回的对象支持迭代接口,即成员方法__next()__继续从中断处执行执行。

但不同于一般的函数:

一般函数一次性返回所有数值的数组,而生成器函数一次只产生数组中的一个值,这样消耗的内存会大大减少;

一般函数执行完毕后返回值并退出,而生成器函数利用yield关键字,给调用者返回一个值,保留当前执行状态,并自动挂起,便于后面next调用时继续执行。

生成器使用next()函数会比较繁琐,而for循环可以为生成器自动触发next函数。

python中生成器有两种方式:

  • **生成器函数:**也是用def来定义,利用关键字yield一次返回一个结果,阻塞,重新开始
  • **生成器表达式:**返回一个对象,这个对象只有在需要的时候才产生结果

上面我们应用了生成器函数,那么生成器表达式是什么呢?

生成器表达式和列表解析类似,但它使用圆括号,而列表解析式用中括号。

# 列表解析式
list = [ x**2 for x in range(5)]
print(list)
[0, 1, 4, 9, 16]

# 生成器表达式
generator_list = (x**2 for x in range(5))
print(generator_list)
<generator object <genexpr> at 0x0EE83840>
print(next(generator_list))
0
print(next(generator_list))
1
print(next(generator_list))
4
print(next(generator_list))
9
print(next(generator_list))
16
print(next(generator_list))
Traceback (most recent call last):
  File "<input>", line 1, in <module>
StopIteration

测试代码

# python 读取较大数据文件

import psutil

mem = psutil.virtual_memory()
print('运行前:')
print('系统总计内存:%d.3M' % (float(mem.total)/1024/1024))
print('系统已经使用内存:%d.3M' % (float(mem.used)/1024/1024))
print('系统空闲内存:%d.3M' % (float(mem.free)/1024/1024))


file_path = 'H:\\study\\python\\long.txt'

# 读取方式一
# with open(file_path, 'r+', encoding='utf-8') as f:
#     count = 0
#     for line in f.readlines():
#         count += 1
#     print(count)

# 读取方式二
# with open(file_path, 'r+', encoding='utf-8') as f:
#     count = 0
#     for line in f:
#         count += 1
#     print(count)


# 读取方式三
def read_fileline_generator(file, size=4096):
    while 1:
        data = file.read(size)
        if not data:
            break
        yield data


with open(file_path, 'r+', encoding='utf-8') as f:
    count = 0
    for line in read_fileline_generator(f):
        count += 1

mem2 = psutil.virtual_memory()
print('运行后:')
print('系统总计内存:%d.3M' % (float(mem2.total) / 1024 / 1024))
print('系统已经使用内存:%d.3M' % (float(mem2.used) / 1024 / 1024))
print('系统空闲内存:%d.3M' % (float(mem2.free) / 1024 / 1024))
知秋君
上一篇 2024-07-19 19:02
下一篇 2024-07-19 18:36

相关推荐