【问题标题】:A list with 70 MB on disk but 500MB in memory磁盘上有 70 MB 但内存中有 500 MB 的列表
【发布时间】:2014-03-23 12:27:01
【问题描述】:

我有一个字符串元组的 python 列表,格式为:lst = [('xxx', 'yyy'), ...etc]。该列表大约有 8154741 元组。我使用了一个分析器,它说该列表需要大约 500 MB 的内存。 然后我将列表中的所有元组写入一个文本文件,磁盘大小约为 72MB。

我有三个问题:

  • 为什么内存消耗与磁盘使用不同?

  • 为这样的列表消耗 500MB 内存是否合乎逻辑?

  • 有没有办法/技术来减小列表的大小?

【问题讨论】:

标签: python list


【解决方案1】:

你有 8154741 元组,这意味着你的列表,假设 8 字节指针,已经包含 62 MB 的元组指针。 假设每个元组在 python2 中包含两个 ascii 字符串,那就是每个元组的另一个 124 MB 指针。 然后你仍然有元组和字符串对象的开销,每个对象都有一个引用计数,假设它是一个 8 字节整数,你还有另一个 186 MB 的引用计数存储。这已经是46 MB 数据的372 MB 开销,您将拥有两个大小为2 元组的3 字节长字符串。 在 python3 下,您的数据是 unicode,每个字符也可能大于 1 个字节。

所以是的,预计这种类型的结构会消耗大量多余的内存。

如果您的字符串都具有相似的长度并且元组都具有相同的长度,那么减少这种情况的方法是使用 numpy 字符串数组。它们将字符串存储在一个连续的内存块中,避免了对象开销。但是如果字符串的大小变化很大,这将无法正常工作,因为 numpy 不支持不规则数组。

>>> d = [("xxx", "yyy") for i in range(8154741)]
>>> a = numpy.array(d)
>>> print a.nbytes/1024**2
46
>>> print a[2,1]
yyy

【讨论】:

  • 我注意到访问一个numpy数组比访问python列表慢,为什么?
  • numpy 针对一次对大量元素应用通用操作进行了优化,访问单个元素没有得到很好的优化并且开销很大。如果速度太慢,您可以仅使用 numpy 存储容器并将内存友好的块提取到纯 python 结构中进行处理。
【解决方案2】:

Python 对象可能比其中的原始数据占用更多的内存。这是因为要实现 Python 的高级和超高速数据结构的特性,您必须创建一些中间和临时对象。 阅读更多here

解决此问题有多种方法,请参阅案例研究here。在大多数情况下,为您的应用程序找到最合适的 Python 数据类型就足够了(在您的情况下使用 numpy 数组而不是列表会不会更好?)。为了进行更多优化,您可以迁移到 Cython,在那里您可以直接声明变量的类型(以及大小),就像在 C 中一样。

还有像IOPro 这样的包,它们试图优化内存使用(不过这个是商业的,有人知道免费包吗?)。

【讨论】:

    【解决方案3】:

    那么字符串大部分是共享的还是唯一的? 元组的意义是什么:词袋或skip-gram表示? 如果是这样,一个很好的词向量表示库是word2vec

    这是一个很好的article on optimizing word2vec's performance

    您是否真的需要将字符串内容保存在内存中,或者您可以转换为特征向量,然后将字符串特征对应关系写入磁盘?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-29
      • 2014-05-07
      • 1970-01-01
      • 2017-10-08
      • 1970-01-01
      • 2015-09-13
      相关资源
      最近更新 更多