左から切り捨てられるPythonバッファーですか?
-
06-07-2019 - |
質問
今、文字列、StringIO、またはcStringIOを使用してバイトをバッファリングしています。しかし、バッファーの左側からバイトを削除する必要がよくあります。単純なアプローチでは、バッファ全体が再構築されます。左切り捨てが非常に一般的な操作である場合、これを行う最適な方法はありますか? Pythonのガベージコレクターは実際に、切り捨てられたバイトをGCする必要があります。
このためのあらゆる種類のアルゴリズム(バッファを小さな断片に維持しますか?)、または既存の実装が本当に役立ちます。
編集:
このためにPython 2.7のメモリビューを使用しようとしましたが、悲しいことに、「ビュー」外のデータは元の参照が削除されたときに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 '.',
解決
A deque は、左削除操作が有効な場合に効率的です。頻繁(リスト、文字列、またはバッファを使用する場合とは異なり、両端削除のためにO(1)が償却されます)。ただし、パックされたシーケンスではなく、各文字を独自の文字列オブジェクトとして保存するため、文字列よりもメモリ的にコストがかかります。
別の方法として、独自の実装(たとえば、固定サイズの文字列/バッファオブジェクトのリンクリスト)を作成して、データをよりコンパクトに保存することもできます。
他のヒント
文字または行のリストとしてバッファを構築し、リストをスライスします。出力時に文字列としてのみ結合します。これは、ほとんどのタイプの「可変文字列」動作に対して非常に効率的です。
GCは、リストで参照されなくなったため、切り捨てられたバイトを収集します。
UPDATE:リストヘッドを変更するには、リストを単に逆にすることができます。これは非効率的なことのように思えますが、Pythonのリスト実装はこれを内部的に最適化します。
http://effbot.org/zone/python-list.htm:
反転は高速なので、一時的に 多くの場合、リストを逆にすると速度が上がります あなたが削除する必要がある場合のものと でアイテムの束を挿入します リストの先頭:
L.reverse() # append/insert/pop/delete at far end L.reverse()