Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 将文件长时间保存在内存中_Python_Memory Management_Large Files - Fatal编程技术网

Python 将文件长时间保存在内存中

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) 我想知道,如果程序要运行很长时间,这样做是否会面临内存管理问题。无论需要多长时间,包含完整内容的文件是否会在内存

我正在处理一个相对较大的文件(大约2GB)。它的内容在运行至少1-2天的while循环中不断需要

有了足够的RAM,我在循环之前将整个文件加载到内存中,使用:

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)