【问题标题】:Python, any alternative to memory dict consuming less memory for key=>value accessPython,内存字典的任何替代方案都为键=>值访问消耗更少的内存
【发布时间】:2018-02-06 08:02:44
【问题描述】:

使用 Python 2.7.x 系列,我遇到以下问题,我需要一个 dict 结构,以便在 D[key] = value 的基础上快速访问,所以 dict 应该是完美的。

顺便说一句,我有MemoryError,因为我需要在内存中有两个对象族,它们都很大(数亿)并且链接:这个字典以及链接树对象的结构(实际上尝试) .

是否有任何替代 dict python 对象具有非常低的内存占用?

值将是一个“id”(字符串),键是一个 * Unicode * 字符串(所以对于重音字符和其他奇怪的字符,我似乎无法将 intern 构造用作 Unicode)。

是否有任何工具可以帮助我,即使散列过程的性能略有下降(不是太多;))。这种设计有哪些常见的良好实践? (我想避免依赖外部数据库的解决方案,因为这个过程已经很慢了,而且我需要太多的这些对象访问。)

【问题讨论】:

  • 你的意思是low memory footprint而不是low fingerprint memory
  • python > 3.6 字典
  • 你说相反的话:你需要快速访问所以不要访问外部数据库,同时你没有足够的内存。我只能看到两种方法:使用更快的磁盘或购买额外的内存...
  • @ReblochonMasque 他们不是已经在 3.6 中变得更好了吗?
  • 是的,我的错;我的意思是从 3.6 开始

标签: python dictionary memory-efficient


【解决方案1】:

shelve 模块提供了一个可以满足您需求的持久字典:

>>> import shelve
>>> db = shelve('cache.db')
>>> db = shelve.open('cache.db')
>>> db['id1'] = u'string data'
>>> db['id1']
'string data'

您可以像使用普通字典一样使用它,但它将所有数据存储在文件(数据库)中的键值存储中。这可能足以满足您的需求,因为后台正在进行一些缓存。尝试它的工作量应该很小。

【讨论】:

    【解决方案2】:

    您有多种选择:

    • 切换到 Python 3.6。

    字典在 3.6 中得到了改善。速度更快,占用空间更小,默认排序,我确定我忘记了一些东西。

    • 获取更多内存。

    您显然是在不符合要求的机器上做一些受内存限制的事情。购买更多 RAM,或租用 m4.xlarge AWS 实例,或其他方式。

    • 重新定义问题。

    您是否需要一次将所有数百万个项目存储在内存中?你是在同时处理它们吗?几乎绝对不是。更智能地编写算法,一次处理数据块,甚至一次处理项目。如果你让这个并发(not necessarily parallel),大部分等待时间将是 IO,并且可以很容易地在 Python 中线程化。

    尝试使用生成器表达式和生成器。它们的内存使用量很小。

    • 使用数据库

    数据库专门用来解决这个问题。编写一个小型导入器将您的数据放入 MySQL 或 MongoDB,然后用 SQL 表达您的问题。

    【讨论】:

    • 不相信 Python 3.6 选项。我试过sys.getsizeof({str(i): str(i) for i in range(10**6)})。 Python 2.7.14 说 25165964,Python 3.6.4 说 25165888。几乎一样,只是相差 76。
    • 那是因为您使用的是顺序键。看看Raymond Hettinger's excellent talk
    • 我最近已经看过了。他的空间效率广告是针对大小为 5 的字典,这些字典非常小,以至于 76 个字节确实很重要。但是对于 OP 的“数亿”项目来说,这不算什么。另外,“顺序键”是什么意思?
    • 您的密钥是按顺序排列的。 0, 1, 2... 观察。 Python 2:getsizeof({randint(0,100000): str(uuid4()) for i in xrange(10000)}) = 786,712。 Python 3:getsizeof({randint(0, 100000): str(uuid4()) for i in range(10000)}) = 393,312。
    • 不,我的密钥是'0''1''2'... 而你最好也是字符串,因为这就是 OP 所拥有的。另外,10000 的大小仍然无法与“许多亿”相提并论。
    猜你喜欢
    • 2011-02-13
    • 2010-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-16
    • 1970-01-01
    相关资源
    最近更新 更多