【问题标题】:A Python buffer that you can truncate from the left?可以从左侧截断的 Python 缓冲区?
【发布时间】:2010-11-03 14:51:20
【问题描述】:

现在,我正在使用字符串、StringIO 或 cStringIO 缓冲字节。但是,我经常需要从缓冲区的左侧删除字节。一种天真的方法将重建整个缓冲区。如果左截断是一种非常常见的操作,是否有最佳方法来做到这一点? Python 的垃圾收集器实际上应该对截断的字节进行 GC。

任何类型的算法(将缓冲区分成小块?),或现有的实现,都会有帮助。

编辑:

我尝试为此使用 Python 2.7 的 memoryview,但遗憾的是,当原始引用被删除时,“视图”之外的数据不会被 GC:

# (This will use ~2GB of memory, not 50MB)

memoryview # Requires Python 2.7+

smalls = []

for i in xrange(10):
    big = memoryview('z'*(200*1000*1000))
    small = big[195*1000*1000:]
    del big
    smalls.append(small)
    print '.',

【问题讨论】:

  • 为什么要删除字节?为什么不使用缓冲区并在完成后丢弃整个缓冲区?
  • 整行(由任意分隔符分隔)正在从缓冲区中增量提取并发送到回调。保留缓冲区可能会耗尽内存。
  • “可能耗尽内存”?真的吗?有这方面的证据吗?在你有证据表明你实际上已经耗尽了内存之前,过度优化这样的事情很少有帮助。

标签: python string buffer memoryview


【解决方案1】:

将缓冲区构建为字符或行的列表,然后对列表进行切片。仅在输出时作为字符串加入。这对于大多数类型的“可变字符串”行为非常有效。

GC 将收集截断的字节,因为它们不再在列表中被引用。

更新:要修改列表头,您可以简单地反转列表。这听起来像是一件低效的事情,但是 python 的列表实现在内部对此进行了优化。

来自http://effbot.org/zone/python-list.htm

倒车很快,所以暂时 颠倒列表通常可以加快速度 如果您需要删除和 在 列表开头:

L.reverse()
# append/insert/pop/delete at far end
L.reverse()

【讨论】:

  • 如果您在这里关心效率,您可能希望使用数组模块中的数组。
  • 列表将与左侧删除的缓冲区存在相同的问题(但内存分配除外) - 它们必须复制每个字节以填充删除造成的漏洞。
  • 它不是在复制字节,而是在复制引用。如果您逐行添加和删除,开销将是最小的。如果没有,您可以反转列表(请参阅上面的答案)
  • 在处理时复制引用比字符更​​糟糕 - 您需要为每个条目复制 4 个字节而不是 1 个。虽然反转是一个不错的解决方案 - 一次性反转成本可以防止每次删除的成本,所以很长时间因为您不需要在反向之后附加更多数据。
【解决方案2】:

如果左删除操作频繁,deque 将是有效的(与使用列表、字符串或缓冲区不同,它的任一端删除的摊销 O(1))。但是,它在内存方面比字符串更昂贵,因为您将每个字符存储为自己的字符串对象,而不是打包序列。

或者,您可以创建自己的实现(例如,固定大小的字符串/缓冲区对象的链表),这样可以更紧凑地存储数据。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-08
相关资源
最近更新 更多