python readline_Python readlines()用法和有效的阅读练习

简短版本是:The efficient way to use readlines() is to not use it. Ever.

I read some doc notes on readlines(), where people has claimed that this readlines() reads whole file content into memory and hence generally consumes more memory compared to readline() or read().

readlines()的文档明确保证它将整个文件读入内存,并将其解析为行,并构建一个完整的字符串列表.

但是read()的文档同样保证它将整个文件读入内存,并构建一个字符串,这样做无济于事.

除了使用更多内存之外,这也意味着在读取整个内容之前,您无法完成任何工作.如果您以最天真的方式交替阅读和处理,您将受益于至少一些流水线操作(由于操作系统磁盘缓存,DMA,CPU管道等),因此您将在下一批时处理一个批处理正在阅读.但是,如果您强制计算机读取整个文件,然后解析整个文件,然后运行您的代码,您只能获得整个文件的一个重叠区域,而不是每个读取重叠工作的一个区域.

您可以通过以下三种方式解决此问题:

>在readlines(sizehint),read(size)或readline()周围写一个循环.

>只需将文件用作惰性迭代器而不调用其中任何一个.

> mmap该文件,它允许您将其视为一个巨大的字符串,而无需先读取它.

例如,这必须立即读取所有foo:

with open('foo') as f:

lines = f.readlines()

for line in lines:

pass

但这一次只能读取大约8K:

with open('foo') as f:

while True:

lines = f.readlines(8192)

if not lines:

break

for line in lines:

pass

而且这一次只能读取一行 – 虽然Python允许(并且将)选择一个漂亮的缓冲区大小以使事情更快.

with open('foo') as f:

while True:

line = f.readline()

if not line:

break

pass

这将完成与前一个完全相同的事情:

with open('foo') as f:

for line in f:

pass

与此同时:

but should the garbage collector automatically clear that loaded content from memory at the end of my loop, hence at any instant my memory should have only the contents of my currently processed file right ?

Python没有对垃圾收集做出任何此类保证.

CPython实现碰巧使用refcounting for GC,这意味着在你的代码中,一旦file_content被反弹或消失,巨大的字符串列表及其中的所有字符串将被释放到空闲列表中,这意味着相同的记忆可以再次用于你的下一次传球.

但是,所有这些分配,复制和解除分配都不是免费的 – 不执行它们比执行它们要快得多.

最重要的是,让你的字符串分散在一大块内存中,而不是一遍又一遍地重复使用相同的小块内存会损害你的缓存行为.

另外,虽然内存使用量可能是恒定的(或者更确切地说,是最大文件大小的线性,而不是文件大小的总和),但第一次扩展它的mallocs的速度将是最慢的你做的事情(这也使得进行性能比较变得更加困难).

总而言之,这就是我编写程序的方式:

for filename in os.listdir(input_dir):

with open(filename, 'rb') as f:

if filename.endswith(".gz"):

f = gzip.open(fileobj=f)

words = (line.split(delimiter) for line in f)

... my logic ...

或者可能:

for filename in os.listdir(input_dir):

if filename.endswith(".gz"):

f = gzip.open(filename, 'rb')

else:

f = open(filename, 'rb')

with contextlib.closing(f):

words = (line.split(delimiter) for line in f)

... my logic ...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值