Ahoi。私はBit.ly's Data_Hacks' sample.pyのパフォーマンスを実践的な練習として改善することを任されました。条件に基づいて線を省略してファイルを反復処理する
私はコードの一部をcythonizedしています。 PCG乱数生成器を含んでいました。これは、これまでに約20秒(72秒から)短縮され、印刷出力を最適化します(pythonのwrite()
の代わりに、基本的なc関数を使用しています)。
これはすべてうまくいきましたが、これらの修正を除いて、ループ自体を最適化したいと思います。
bit.lyのsample.py
に見られるように、基本的な機能、:
def run(sample_rate):
input_stream = sys.stdin
for line in input_stream:
if random.randint(1,100) <= sample_rate:
sys.stdout.write(line)
私の実装:
cdef int take_sample(float sample_rate):
cdef unsigned int floor = 1
cdef unsigned int top = 100
if pcg32_random() % 100 <= sample_rate:
return 1
else:
return 0
def run(float sample_rate, file):
cdef char* line
with open(file, 'rb') as f:
for line in f:
if take_sample(sample_rate):
out(line)
私は今改善したいと思いますどのような具体的に(次の行をスキップして、 take_sample()がTrue
を返さない場合は、繰り返し実行することをお勧めします。
私の現在の実装はこれです:
def run(float sample_rate, file):
cdef char* line
with open(file, 'rb') as f:
for line in f:
out(line)
while not take_sample(sample_rate):
next(f)
パフォーマンスを向上させるために何もしないように思われる - 私は、ループの先頭であれば条件の後continue
コールを単に交換してきた疑いがあるために私をリードします私のnext(f)
。
そこで質問はこれです:
は(Cythonで)ファイルをループするより効率的な方法はありますか?
私は私out()
を呼び出す場合、彼らは唯一の真にアクセスする必要がある意味、完全にラインを省略したいと思います - これは、すでにPythonのfor
ループの場合ですか? line
はファイルの行にポインタ(またはそれに相当する)ですか?または、ループは実際にこれをロードしますか?
私はそれをC言語で完全に書くことで改善できることを認識していますが、これをpython/cythonでどれくらい押し込むことができるかを知りたいと思います。
更新: 私は、同じテストケースを使用して、自分のコードのC変種をテストしました.2秒未満でクロックインしました(驚くべき誰もいない)。だから、ランダムジェネレータとファイルI/Oは一般的に言って2つの主要なボトルネックですが、pythonのファイル処理自体はまだ遅いと指摘されるべきです。
したがって、ループ自体をcythonに実装する以外に、Cのファイル読み込みを利用する方法はありますか?オーバーヘッドはまだPythonコードを大幅に減速させています。これは、私が単にパフォーマンスの音の壁にいるのか、それともCythonを使ったファイルハンドリングにあるのだろうかと思います。
この書き込みは、以下のような助けになるかもしれません。http://rabexc.org/posts/io-performance-in-python –
ボトルネックはファイルIOとランダム関数です。元のスクリプトには、最適化の可能性はほとんどありません。 – Daniel
'f'の各反復は1行を読み込みます。行は、次の '\ nl'までのバイト列として定義されます。読者がそれを見つける唯一の方法は、バイトを1つずつ読むことです。テキストの場合、 'seek'に使うことができる行の始まりのインデックスはありません。したがって、電流を読み取らずに次の行にスキップすることはできません。 – hpaulj