17

ファイルを1行ずつ読み取り、各行が正規表現と一致するかどうかを調べるPythonスクリプトがあります。

検索する前にメモリ マップ ファイルを使用して、そのスクリプトのパフォーマンスを向上させたいと考えています。mmap の例を調べました: http://docs.python.org/2/library/mmap.html

私の質問は、マシンのメモリ (4GB) に対してファイルが大きすぎる (15GB) 場合、どうすればファイルを mmap できるかということです。

私は次のようにファイルを読みました:

fi = open(log_file, 'r', buffering=10*1024*1024)

for line in fi: 
    //do somemthong

fi.close()

バッファを10MBに設定したので、性能的には10MBのファイルをmmapしたのと同じですか?

ありがとうございました。

4

2 に答える 2

34

まず、マシンのメモリは関係ありません。関連するのは、プロセスのアドレス空間のサイズです。32 ビットの Python では、これは 4GB 未満になります。64 ビットの Python では、これで十分です。

この理由は、ファイルを物理メモリにマッピングすることでmmapはなく、仮想メモリにマッピングすることです。ped ファイルは、プログラムの特別なスワップ ファイルのようになります。これについて考えると少し複雑になる可能性がありますが、上記のウィキペディアのリンクが役立つはずです。mmap

したがって、最初の答えは「64 ビットの Python を使用する」です。しかし、明らかにそれはあなたの場合には当てはまらないかもしれません。

明らかな代替手段は、最初の 1GB にマップし、それを検索し、マップを解除し、次の 1GB にマップする、などです。これを行う方法は、メソッドにパラメータlengthoffsetパラメータを指定することmmapです。例えば:

m = mmap.mmap(f.fileno(), length=1024*1024*1024, offset=1536*1024*1024)

ただし、探している正規表現は、最初の 1 GB の半分と 2 番目の半分で見つかる可能性があります。したがって、ウィンドウ処理を使用する必要があります。つまり、最初の 1 GB でマップし、検索してマップ解除し、部分的に重複する 1 GB でマップする、などです。

問題は、どのくらいのオーバーラップが必要かということです。一致の最大可能サイズがわかっている場合は、それ以上のものは必要ありません。わからない場合は、正規表現を分割せずに問題を実際に解決する方法はありません。それが明らかでない場合は、単一の 1 GB ウィンドウで 2 GB の一致を見つける方法を想像してみてください。

フォローアップの質問に答える:

バッファを10MBに設定したので、性能的には10MBのファイルをmmapしたのと同じですか?

他のパフォーマンスの問題と同様に、本当に重要な場合はテストする必要があります。そうでない場合は、心配する必要はありません。

あなたが私に推測してもらいたい場合:私はmmapここでより速いかもしれないと思いますが、(JF Sebastianが暗示したように)ループしてre.match128K回呼び出すと、コードがIOバウンドではなくCPUバウンドになる可能性があるためです。mmapただし、を使用するだけで、を使用せずに最適化できますread。それで、mmapより速いでしょうreadか?mmap関連するサイズを考えると、 のパフォーマンスは、古い Unix プラットフォームでははるかに速く、最新の Unix プラットフォームではほぼ同じで、Windows では少し遅くなると思います。(を使用している場合でも、 mmapoverreadまたはread+から大きなパフォーマンス上の利点を得ることができますが、ここでは関係ありません。) しかし、実際には、それは単なる推測です。lseekmadvise

使用する最も説得力のある理由mmapは、通常、readベースのコードよりも単純であり、高速だからではありません。でさえウィンドウ操作を使用するmmap必要があり、 でシークを行う必要がない場合read、これはそれほど魅力的ではありませんが、それでも、両方の方法でコードを記述しようとすると、mmapコードが少し終わると思いますより読みやすく。(特に、明白なread解決策からバッファ コピーを最適化しようとした場合)。

于 2013-01-12T02:04:25.777 に答える
1

mmap数十GBのファイルを使っfileh.readline()ていて、もっと速くしたかったので使ってみました。Unixstraceユーティリティは、ファイルが現在 4kB のチャンクで読み取られていることを明らかにしているようで、少なくとも strace からの出力はゆっくりと印刷されているように見え、ファイルの解析には何時間もかかることがわかっています。

$ strace -v -f -p 32495
Process 32495 attached
read(5, "blah blah blah foo bar xxxxxxxxx"..., 4096) = 4096
read(5, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 4096) = 4096
read(5, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 4096) = 4096
read(5, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 4096) = 4096
^CProcess 32495 detached
$

mmapこのスレッドは、これまでのところ、大きすぎるファイルを試してはならないことを説明している唯一のものです。mmap_for_dummies(filename)内部で os.path.size(filename) を実行し、通常のopen(filename, 'r', buffering=10*1024*1024)実行または実行するようなヘルパー関数がまだ存在しない理由がわかりませんmmap.mmap(open(filename).fileno())。私は確かに自分でスライディングウィンドウアプローチをいじるのを避けたいと思っていますが、関数は実行するかどうかを簡単に決定するmmapだけで十分です。

open(filename, 'rb')最後に、インターネット上のいくつかの例が説明なしで言及されている理由はまだ明確ではありません(例: https://docs.python.org/2/library/mmap.html )。for ループでファイルを呼び出して使用したいことがよくある場合、モードで開く必要があるのか​​ 、それとも単にモード.readline()で開く必要があるのか​​ わかりません(を保存する必要があると思います)。'rb''r''\n'

議論に言及していただきありがとうございbuffering=10*1024*1024)ます。速度を上げるためにコードを変更するよりもおそらく役立つでしょう。

于 2016-04-04T23:12:42.447 に答える