Буфер Python, который можно обрезать слева?
-
06-07-2019 - |
Вопрос
Прямо сейчас я буферизую байты, используя строки, StringIO или cStringIO.Но мне часто нужно удалить байты из левой части буфера.Наивный подход перестроил бы весь буфер.Есть ли оптимальный способ сделать это, если усечение влево — очень распространенная операция?Сборщик мусора Python должен фактически собирать усеченные байты.
Любой алгоритм для этого (хранить буфер небольшими частями?) или существующая реализация действительно помогли бы.
Редактировать:
Я пытался использовать для этого представление памяти Python 2.7, но, к сожалению, данные за пределами «представления» не собираются при удалении исходной ссылки:
# (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 '.',
Решение
А дек будет эффективен, если операции удаления слева часты (в отличие от использования списка, строки или буфера, для удаления с любого конца амортизируется O(1).Однако это будет более затратно с точки зрения памяти, чем строка, поскольку вы будете хранить каждый символ как отдельный строковый объект, а не как упакованную последовательность.
Альтернативно вы можете создать свою собственную реализацию (например.связанный список строковых/буферных объектов фиксированного размера), который может хранить данные более компактно.
Другие советы
Создайте свой буфер в виде списка символов или строк и разрежьте этот список.Присоединяйтесь только как строка на выходе.Это довольно эффективно для большинства типов поведения «изменяемой строки».
Сборщик мусора соберет усеченные байты, поскольку на них больше нет ссылок в списке.
ОБНОВЛЯТЬ:Для изменения заголовка списка вы можете просто перевернуть список.Это звучит как неэффективная вещь, однако реализация списка в Python оптимизирует это внутренне.
от http://effbot.org/zone/python-list.htm :
Реверсирование - это быстрая, поэтому временное изменение списка часто может ускорить ситуацию, если вам нужно удалить и вставить кучу элементов в начале списка:
L.reverse() # append/insert/pop/delete at far end L.reverse()