17

そのため、かなり巨大な .gz ファイルがいくつかあります。解凍すると、それぞれ 10 ~ 20 GB になります。

それらの各行をループする必要があるため、標準を使用しています:

import gzip
f = gzip.open(path+myFile, 'r')
for line in f.readlines():
    #(yadda yadda)
f.close()

ただし、コマンドopen()close()コマンドはどちらも AGES を使用し、メモリ + CPU の 98% を使用します。プログラムが終了Killedして端末に出力されるほどです。たぶん、抽出されたファイル全体をメモリにロードしていますか?

私は今、次のようなものを使用しています:

from subprocess import call
f = open(path+'myfile.txt', 'w')
call(['gunzip', '-c', path+myfile], stdout=f)
#do some looping through the file
f.close()
#then delete extracted file

これは機能します。しかし、よりクリーンな方法はありますか?

4

2 に答える 2

59

あなたの問題は ではなく にあると 99% 確信していgzip.open()ますreadlines()

ドキュメントで説明されているように:

f.readlines() は、ファイル内のすべてのデータ行を含むリストを返します。

明らかに、それにはファイル全体の読み取りと解凍が必要であり、非常に巨大なリストを作成する必要があります。

ほとんどの場合、実際にはmallocすべてのメモリを割り当てるための呼び出しが永遠にかかっています。そして、このスコープの最後で (CPython を使用していると仮定して)、巨大なリスト全体を GC する必要があり、これにも永遠に時間がかかります。

を使用することはほとんどありませんreadlines。非常に古い Python を使用している場合を除き、次のようにします。

for line in f:

Aは、によって返されるfileのと同じように、行でいっぱいの iterable です。実際には aではないことを除いて、バッファから読み取ることにより、その場でさらに行を生成します。したがって、いつでも、25GB ではなく、1 行とそれぞれ 10MB 程度のバッファが 2 つだけになります。また、読み取りと圧縮解除は、一度にすべて実行されるのではなく、ループの存続期間全体に分散されます。listreadlineslistlist

3.5 GB の gzip ファイルを使用した簡単なテストでは、gzip.open()事実上瞬時に実行されfor line in f: pass、数秒かかり、gzip.close()事実上瞬時に実行されます。しかし、そうするとfor line in f.readlines(): pass、時間がかかります…まあ、どれくらいかかるかわかりません.1分ほどすると、私のシステムはスワップスラッシング地獄に入り、何かに応答させるためにインタープリターを強制終了しなければなりませんでした…</p >


これはこの回答以来何十回も出てきたので、もう少し説明するこのブログ投稿を書きました.

于 2013-02-01T22:26:12.803 に答える
2

パンダ、特に IO tools を見てください。ファイルの読み取り時に gzip 圧縮をサポートし、ファイルをチャンクで読み取ることができます。その上、pa​​ndas は非常に高速でメモリ効率が良いです。

試したことがないので、圧縮とチャンクでの読み取りがどの程度うまく連携しているかはわかりませんが、試してみる価値があるかもしれません

于 2013-02-01T22:28:36.340 に答える