Python 将文件长时间保存在内存中
我正在处理一个相对较大的文件(大约2GB)。它的内容在运行至少1-2天的while循环中不断需要 有了足够的RAM,我在循环之前将整个文件加载到内存中,使用:Python 将文件长时间保存在内存中,python,memory-management,large-files,Python,Memory Management,Large Files,我正在处理一个相对较大的文件(大约2GB)。它的内容在运行至少1-2天的while循环中不断需要 有了足够的RAM,我在循环之前将整个文件加载到内存中,使用: f = open(filename) lines = f.readlines() while ... #using different portions of the file (randomly picked) 我想知道,如果程序要运行很长时间,这样做是否会面临内存管理问题。无论需要多长时间,包含完整内容的文件是否会在内存
f = open(filename)
lines = f.readlines()
while ...
#using different portions of the file (randomly picked)
- 我想知道,如果程序要运行很长时间,这样做是否会面临内存管理问题。无论需要多长时间,包含完整内容的文件是否会在内存中保持完整?如果没有,我还有什么选择
- 当然,一开始我确实试着做一些正确的事情,只读取循环每次迭代所需的部分,使用itertools中的islice,并使用seek(0)将迭代器设置回0,为循环的后续运行做准备。但是它运行非常慢,因为文件很大,while循环很长
更多澄清,在评论之后: 当我没有在内存中加载它时,我基本上是这样做的:
from itertools import islice
f = open(filename)
while ...:
for line in islice(f, start_line, end_line):
text += line
f.seek(0)
与我在内存中加载所有内容时相比,速度非常慢,如下所示:
lines = f.readlines()
while...:
for i in range(start_line, end_line): text += lines[i]
内存中保存的数据类型是一个列表,而不是一个文件对象,因此Python将特别小心,不要在稍后使用该列表时对其进行垃圾收集 如果你没有按顺序使用它,这并不重要。Python在编译代码之前分析代码,他知道您稍后将使用此列表 无论如何,如果您在file对象上使用seek()和tell(),我不明白为什么它会很慢 除非你的线条像大象一样大 Seek将读/写指针移动到所需的内存块(文件内部)。当您随后执行f.readline()时,它会直接跳到那里 不应该太慢。如果您使用它,您将避免其他程序崩溃的可能性,因为Python保留了大量内存 此外,Python列表并不是完全不确定的。我认为它可以在32位PC上容纳10*7个以上的项目 所以你有多少行也很重要 直接从HD/SSD/Flash快速随机线读取示例:
from random import randint
from time import sleep
f = open("2GB.file", "rb")
linemap = [] # Keeps the start and end position of each line
for x in f:
linemap.append((f.tell(), len(x)))
# It is slightly faster to have start and length than only start and then f.readline()
# But either way will work OK for you
def getline (index):
line = linemap[index]
f.seek(line[0])
return f.read(line[1])
def getslice (start=0, stop=None):
if stop==None: stop = len(linemap)
howmany = 0
for x in xrange(start, stop): howmany += linemap[x][1]
f.seek(linemap[start][0])
return f.read(howmany).splitlines(1)
while True:
print getline(randint(0, len(linemap)-1))
sleep(2)
当然,速度永远无法与RAM的直接访问相匹配。我只是想说清楚。但与您使用islice()的解决方案相比,这简直是雷霆万钧。虽然您实际上可以使用islice()以相同的速度执行相同的操作,但即使这样,您也必须进行搜索,代码也会变得有点混乱。根据我的注释进行解释,您可以创建一个函数来返回内存中的字节缓冲区,并缓存该函数,以便仅对一个变量进行更多控制 例如(如果您使用的是python3.2+、3.3+和“typed”选项):
用法:
a = get_cached_file('a.file')
b = get_cached_file('b.file')
# since the files are new to cache, they belong "misses"
get_cached_file.cache_info()
CacheInfo(hits=0, misses=2, maxsize=None, currsize=2)
a1 = get_cached_file('a.file')
b2 = get_cached_file('b.file')
# simply return the result from cache, ie. "hits"
get_cached_file.cache_info()
CacheInfo(hits=2, misses=2, maxsize=None, currsize=2)
要读取缓冲区,只需seek(0)
或任何您想要的内容
您还可以清除缓存:
get_cached_file.cache_clear()
# now its counter reset to "0"
get_cached_file.cache_info()
CacheInfo(hits=0, misses=0, maxsize=None, currsize=0)
你可以读更多
如果您使用的是python2.x,请查找一些现有的用于在内存中缓存的库,例如memcached或redis。当然,您也可以实现自己的缓存
希望这能有所帮助。除非计算机试图在RAM中加载超出其存储空间的内容,否则,长时间在RAM中加载内容不是问题。计算机不会感到无聊或疲倦。为什么不创建一个函数来返回文件,并缓存函数本身呢?使用缓存比使用内存中的变量有更多的优势,即控制缓存持续时间、使其无效等。尽管所有这些都在内存中。@user929304,答案补充,虽然非常粗略地说,我希望你能理解。如果文件是CSV格式或类似格式,你可能想使用这个库。熊猫有一种非常有效和快速的方法将大文件存储到内存中。求零意味着您正在一次又一次地从头读取文件。在看到您希望使用的工具的代码之前,不要使用itertools中的任何内容。Itertools很方便,但它并非像某些人所希望的那样,在所有用途上都是通用的。首先,enumerate()需要时间和内存。只需要在循环结束时增加另一个变量。第二,只要从列表中取出一个片段,如果您在内存中有:lst[10:50],即lst[start:stop:step],不需要ifs和迭代。这是islice()直接对文件对象执行的操作,但它返回的是迭代器,而不是列表。这意味着您必须使用循环对返回的对象进行迭代,或者调用next()方法获取切片中的第一项,然后再次调用next(),直到引发StopIteration异常。如果您需要这种行为,如果您仍然需要此功能。在得到结果的迭代结束时,调用f.tell()查看您的位置。或者为所有索引(每行的起始位置)创建一个内存映射,并仅将其保留在RAM中。然后,您可以在任何需要的地方查找()。请参阅我的编辑,我添加了一个示例。希望这是你需要的。您应该将注释中的代码示例复制到Q中,而不是只发布伪代码。这样每个人都能更清楚地知道你想要实现什么。没错,但最好像我在我添加的getslice()函数中所做的那样去做。最好一次读取尽可能多的字节。如果愿意,您可以添加linemap作为参数,这没有什么区别,只是您可以同时为更多文件添加更多贴图。那太酷了。@user929304,没问题。正如我所说,它们都存在于内存中,但是您有更多使用缓存的控件,并选择何时使它们无效。
get_cached_file.cache_clear()
# now its counter reset to "0"
get_cached_file.cache_info()
CacheInfo(hits=0, misses=0, maxsize=None, currsize=0)