2016-05-25 2 views
1

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を使ったファイルハンドリングにあるのだろうかと思います。

+1

この書き込みは、以下のような助けになるかもしれません。http://rabexc.org/posts/io-performance-in-python –

+0

ボトルネックはファイルIOとランダム関数です。元のスクリプトには、最適化の可能性はほとんどありません。 – Daniel

+1

'f'の各反復は1行を読み込みます。行は、次の '\ nl'までのバイト列として定義されます。読者がそれを見つける唯一の方法は、バイトを1つずつ読むことです。テキストの場合、 'seek'に使うことができる行の始まりのインデックスはありません。したがって、電流を読み取らずに次の行にスキップすることはできません。 – hpaulj

答えて

0

ファイルが小さい場合は、一度に.readlines()で全体を読み取って(可能であればIOトラフィックを減らすことができます)、一連の行を繰り返します。 サンプルレートが十分に小さい場合、より効率的な幾何分布からのサンプリングを検討することができます。

私はcythonを知らないが、私も検討する:

  • 不要な変数を除去することによってtake_sample()を簡素化し、代わりに整数のテスト結果を表すブール値を返す、take_sample(int)take_sample()
  • 変更署名へテストごとにintからfloatへの変換を避ける。あなたが.read().split('\n')の代わりに、私が提案し.readlines()を使用する場合

[EDIT]

@hpauljのコメントによると、それは良いことがあります。

+0

ファイルは、残念ながら非常に大きなものです。テストケースには約9000万行のテキストがあります。 – nlsdfnbch

+1

@ j4ck同じ目的のためにファイルバッファリングを使用するようです:http://stackoverflow.com/questions/29712445/what-is-the-use-of-buffering-in-pythons-built-in-open-function – abukaj

関連する問題