gpt4 book ai didi

python - 将文件映射到内存

转载 作者:太空宇宙 更新时间:2023-11-04 05:16:56 24 4
gpt4 key购买 nike

考虑一个文件,其内容是一个 pickled python 对象。为了使事情具体化,假设这个对象只是一个字符串列表,但实际上它更复杂。

我的 python 脚本在启动时读取该文件。之后,某些事件会触发读取对象的微小更新(在示例中,字符串会在列表的任何位置添加或删除)。为了使文件保持最新,脚本会选择对象并将其写入文件(即整个文件是从头开始写入的)。

有没有办法避免每次都重写整个对象?我对其他存储数据的方式持开放态度,即不依赖 pickle 。我想我正在寻找某种将文件映射到内存的方法,以便对内存中对象的任何更新都会导致对文件的即时更新。

最佳答案

更新 tl;dr

  • 是的,只有字符串变量适用于索引
  • 对于每个键值对,对值的任何更改都需要将整个值重新写入磁盘
    • 您使用的键越多,值越小,您的磁盘写入量就越小

如果您已经在使用 pickles,我会推荐 pythons 的标准 shelve图书馆。它允许您设置 dbm样式数据库并读/写任何可 pickle 的对象

来自文档:

import shelve

d = shelve.open(filename) # open -- file may get suffix added by low-level
# library

d[key] = data # store data at key (overwrites old data if
# using an existing key)
data = d[key] # retrieve a COPY of data at key (raise KeyError if no
# such key)
del d[key] # delete data stored at key (raises KeyError
# if no such key)
flag = d.has_key(key) # true if the key exists
klist = d.keys() # a list of all existing keys (slow!)

# as d was opened WITHOUT writeback=True, beware:
d['xx'] = range(4) # this works as expected, but...
d['xx'].append(5) # *this doesn't!* -- d['xx'] is STILL range(4)!

# having opened d without writeback=True, you need to code carefully:
temp = d['xx'] # extracts the copy
temp.append(5) # mutates the copy
d['xx'] = temp # stores the copy right back, to persist it

# or, d=shelve.open(filename,writeback=True) would let you just code
# d['xx'].append(5) and have it work as expected, BUT it would also
# consume more memory and make the d.close() operation slower.

d.close() # close it

根据评论,让我解释一些事情..

字符串作为键:

有点像 jar 上说的,你只能用字符串索引键值对。这与可以将任何可散列类型作为键的普通字典不同。例如:

import shelve
database = shelve.open(filename) #open our database
dictionary = {} #create an empty dict

ingredients = ['flour', 'sugar', 'butter', 'water'] #recipe for something tasty

database['pie dough'] = ingredients #works because 'pie dough' is a string
dictionary['pie dough'] = ingredients #works because strings are hashable

recipe = 'pie dough'
database[recipe] = ingredients #you can use a variable as long as it is of <type 'str'>

#say we want to just number our entries..
database[5] = ingredients #won't work because 5 is an integer not a string
dictionary[5] = ingredients #works because integers are hashable

database.close()

可变对象

文档中关于可变对象的声明使用了一些技术措辞,但通常指的是数据驻留在内存中与硬盘驱动器上的结果。基本上,如果您的一个对象是一个列表(一个可变对象),您可以像这样检索它:

mylist = database['pie dough']
#or
mylist = dictionary['pie dough']

我们已经意识到我们需要在这个食谱中加盐,我们的对象是一个列表,所以我们可以相对容易地调用:

mylist.append('salt')

然后我们可以使用简单的赋值将这个新的更新食谱写回数据库或字典

database['pie dough'] = mylist
#or
dictionary['pie dough'] = mylist

此方法将始终适用于数据库和字典。当你想直接引用对象时,区别就来了。当我们可以引用包含在字典中的列表本身时,将 mylist 变量简单地创建为临时变量是多余的:

dictionary['pie dough'].append('salt')

这是字典中的值是对 ram 中原始对象的引用这一事实的直接结果。当您修改 dictionary['pie dough'] 时,您也在修改 mylistingredients,因为它们实际上是同一个对象。当你载入一个对象时使用数据库:mylist = database['pie dough'] 你正在复制硬盘上的内容。您可以随意修改该副本,但它不会更改硬盘驱动器上的内容,因为它不是同一个对象(它是一个副本)。

解决方法是使用关键字 writeback=True 打开数据库。这提供了一些类似的功能,但有一些注意事项......虽然现在可以直接在字典对象上调用 append(...) 而无需制作副本,但更改不会出现,直到你调用dictionary.sync()dictionary.close()。为此,我将从一个新示例开始:

import shelve

d = shelve.open(filename)
d['dough'] = ['flour', 'sugar', 'butter', 'water']
d.close() #write initial recipe to our database

#some time later we want to update the recipe
d = shelve.open(filename, writeback=True)
d['dough'].append('salt')
d.close()

现在,无论何时您访问数据库的一部分,该部分都会加载到 ram 中,并且可以直接对对象进行更新。需要注意的是,在调用 d.close() 之前,更新不会写入硬盘。数据库通常大于系统中所有可用的 ram,并且尝试更新太多对象而不调用 d.sync() 将挂起的更改写入硬盘驱动器或定期关闭和关闭重新打开数据库可能会导致内存不足的问题。

关于python - 将文件映射到内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41469629/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com