14

RAMが問題にならない場合(サーバーに200GB近くあります)、行ごとの読み取りが高速ですか、それともすべてをRAMに読み込んでアクセスしますか?各行は、約200〜500のUnicode文字の文字列になります。各ファイルには200万行近くあります。

1行ずつ

import codecs
for i in codecs.open('unicodefile','r','utf8'):
  print i

RAMへの読み込み

import codecs
for i in codecs.open('unicodefile','r','utf8').readlines():
  print i
4

4 に答える 4

15

〜1MBの辞書単語ファイルでcProfileを使用しました。同じファイルを 3 回読みました。1 つ目は、キャッシュに保存されているという点で、ファイル全体をプレイ フィールドに合わせて読み取ります。簡単なコードは次のとおりです。

def first_read():
    codecs.open(file, 'r', 'utf8').readlines()

def line_by_line():
    for i in codecs.open(file, 'r', 'utf8'):
        pass

def at_once():
    for i in codecs.open(file, 'r', 'utf8').readlines():
        pass

first_read()
cProfile.run('line_by_line()')
cProfile.run('at_once()')

結果は次のとおりです。

1行ずつ:

         366959 function calls in 1.762 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.762    1.762 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 codecs.py:322(__init__)
        1    0.000    0.000    0.000    0.000 codecs.py:395(__init__)
    14093    0.087    0.000    0.131    0.000 codecs.py:424(read)
    57448    0.285    0.000    0.566    0.000 codecs.py:503(readline)
    57448    0.444    0.000    1.010    0.000 codecs.py:612(next)
        1    0.000    0.000    0.000    0.000 codecs.py:651(__init__)
    57448    0.381    0.000    1.390    0.000 codecs.py:681(next)
        1    0.000    0.000    0.000    0.000 codecs.py:686(__iter__)
        1    0.000    0.000    0.000    0.000 codecs.py:841(open)
        1    0.372    0.372    1.762    1.762 test.py:9(line_by_line)
    13316    0.011    0.000    0.023    0.000 utf_8.py:15(decode)
        1    0.000    0.000    0.000    0.000 {_codecs.lookup}
    27385    0.027    0.000    0.027    0.000 {_codecs.utf_8_decode}
    98895    0.011    0.000    0.011    0.000 {len}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
    13316    0.099    0.000    0.122    0.000 {method 'endswith' of 'unicode' objects}
       27    0.000    0.000    0.000    0.000 {method 'join' of 'str' objects}
    14069    0.027    0.000    0.027    0.000 {method 'read' of 'file' objects}
    13504    0.020    0.000    0.020    0.000 {method 'splitlines' of 'unicode' objects}
        1    0.000    0.000    0.000    0.000 {open}

一斉に:

         15 function calls in 0.023 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.023    0.023 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 codecs.py:322(__init__)
        1    0.000    0.000    0.000    0.000 codecs.py:395(__init__)
        1    0.000    0.000    0.003    0.003 codecs.py:424(read)
        1    0.000    0.000    0.014    0.014 codecs.py:576(readlines)
        1    0.000    0.000    0.000    0.000 codecs.py:651(__init__)
        1    0.000    0.000    0.014    0.014 codecs.py:677(readlines)
        1    0.000    0.000    0.000    0.000 codecs.py:841(open)
        1    0.009    0.009    0.023    0.023 test.py:13(at_once)
        1    0.000    0.000    0.000    0.000 {_codecs.lookup}
        1    0.003    0.003    0.003    0.003 {_codecs.utf_8_decode}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.001    0.001    0.001    0.001 {method 'read' of 'file' objects}
        1    0.010    0.010    0.010    0.010 {method 'splitlines' of 'unicode' objects}
        1    0.000    0.000    0.000    0.000 {open}

結果からわかるように、一度にファイル全体を読み取る方がはるかに高速ですが、ファイルが大きすぎるために MemoryError がスローされるリスクがあります。

于 2013-02-23T10:52:20.050 に答える
8

マシンでこれをテストすることを妨げるものは何もありません。それぞれ100万行のファイルを作成し、結果を

time python something.py > /dev/null

そうだった:

1行ずつ:

real    0m4.878s
user    0m4.860s
sys     0m0.008s

RAM への読み込み:

real    0m0.981s
user    0m0.828s
sys     0m0.148s

2M 行、それぞれ 300 文字で試したときに MemoryError が発生しましたが、上記は RAM への読み取りが高速であることを示唆しています。

于 2013-02-23T10:32:21.093 に答える
6

OPが投稿したサンプルコードを見ると、Pythonが何をしているのかについて誤解があると思います。

すなわち:

「一行ずつ読む」

import codecs
for i in codecs.open('unicodefile','r','utf8'):
  print i

上記は、行ごとに読み取っているように見えます。ただし、Python はこれを「ファイルをできるだけ多くメモリに読み込み、それぞれを 1 行として処理する」と解釈します。つまり、上記の for ループはすべてをメモリに読み込みます。

「RAMへの読み込み」

import codecs
for i in codecs.open('unicodefile','r','utf8').readlines():
  print i

上記は、上記の「行ごと」の例と実質的に同じであると思います。つまり、Python はすべてをメモリに読み込んでいます。

行ごとのパフォーマンスをテストしたい場合は、「readlines()」または「readlines()」を意味する可能性のある未指定の for ループではなく、「readline()」が必要です。これは、StackOverflow サイトの別の場所に記載されています。

考慮すべきもう 1 つの側面は、ファイルシステムのバッファリングです。同じファイルに対して同じビットのコードを実行している場合、ファイルシステムのバッファリングが結果を汚染するリスクがあります。あなたが言うように、200GB の RAM があります。これは、実行結果に影響を与えるのに十分なファイルをバッファリングするのに十分です。

クリーンなテスト結果を確保するには、次のことを行う必要があります。

1) 大きなファイルを既知のソースから新しいファイル名にコピーします。(ファイルシステムは COW ファイルシステムである必要はありません。) 2) ファイルシステムのキャッシュをフラッシュします。3) ファイルに対して最初のテストを実行します。4) ファイルを削除します。5) ファイルをソースから別の新しいファイル名に再コピーします。6) ファイルシステムのキャッシュをフラッシュします。7) 新しいファイルに対して 2 番目のテストを実行します。

これにより、ファイルの読み込み時間をより正確にテストできます。

ファイル全体を一度にメモリにロードしたい場合、 filehandle.read(bytes to read) は、ファイルの内容をブロックで読み取るためのより高速な手段を提供する可能性はありませんか?

どちらの場合も、参考までに:

http://docs.python.org/2/tutorial/inputoutput.html

于 2013-04-03T17:52:05.260 に答える
0

ストリーミング処理 (1 行ずつ) を使用してプログラムを作成することをお勧めします。この場合、大量のデータを処理できます。一般的には、たとえば 100 行を読み取る読み取りを実装し、それらを処理してから、別の 100 行をロードする方が適切です。低レベルでは、大きなバッファを使用しているだけで、元のファイルを大きなチャンクで読み取ります。すべてをメモリにロードすると、@oseiskarが書いたようなメモリエラーが発生する可能性があります

于 2013-04-01T12:09:07.380 に答える