2011-02-10 16 views
21

私はcProfileで継承したいくつかのレガシーコードをプロファイリングしました。すでにシンプルジョーンズのCの拡張機能を使っているような、私がすでに手がけてきた変更がたくさんありました。ファイルへの書き込みを高速化する

基本的に、このスクリプトはあるシステムからASCII固定幅ファイルにデータをエクスポートしています。各行はレコードであり、多くの値を持っています。各行は7158文字で、1トンのスペースが含まれています。総レコード数は150万レコードです。各行は一度に1つずつ生成され、しばらく時間がかかります(1秒あたり5〜10行)。

各行が生成されるたびに、できるだけ簡単にディスクに書き込まれます。プロファイリングは、約の合計時間の19-20%がfile.write()で費やされていることを示しています。 1,500行のテストケースの場合、20秒です。私はその数を減らしたいと思います。

次の勝利は、ディスクへの書き込みに費やされる時間を減らすことになります。可能であれば、それを減らしたいと思います。私はメモリ内のレコードのキャッシュを保持することができますが、私は最後まで待つことはできず、一度にすべてをダンプします。

fd = open(data_file, 'w') 
for c, (recordid, values) in enumerate(generatevalues()): 
     row = prep_row(recordid, values) 
     fd.write(row) 
     if c % 117 == 0: 
       if limit > 0 and c >= limit: 
         break 
       sys.stdout.write('\r%s @ %s' % (str(c + 1).rjust(7), datetime.now())) 
       sys.stdout.flush() 

私の最初の考えは、レコードのキャッシュをリストに保存し、バッチで書き出すことです。それはより速いでしょうか?何かのように:

rows = [] 
for c, (recordid, values) in enumerate(generatevalues()): 
     rows.append(prep_row(recordid, values)) 
     if c % 117 == 0: 
      fd.write('\n'.join(rows)) 
      rows = [] 

私の2番目の考えは、別のスレッドを使用することですが、それは私の中で死ぬことができます。

+0

アプリケーションのボトルネックは何ですか? –

+2

私は明らかだと思った。一度にディスクの1行に20%の書き込み時間を費やしています。 – chmullig

+0

さて、変更してプロファイルしますか?ファイルI/Oは通常バッファリングされているので、効果はほとんどないと思います。 – delnan

答えて

19

500個のグループに書き込みをバッチすると、実際に書き込みが大幅にスピードアップしました。このテストケースでは、I/Oで21.051秒の書き込み行を処理する一方、117のバッチでは同じ行数を書き込むには5.685秒かかりました。 500回分のバッチではわずか0.266秒しかかかりませんでした。

+3

これでasynhronusの書き込みにスレッドを追加することができます。 – ted

+0

stdoutに出力し、ファイルにパイプし、OSにバッファリングとバッチ書き込みをさせます。 :) –

+0

@LesterCheung、あなたは精巧にできますか? – blindguy

32

実際、あなたの問題は、file.write()があなたの時間の20%かかります。あなたはそのうちの80%がfile.write()にいません!

ディスクへの書き込みが遅いです。あなたはそれについて本当に何もできません。ディスクに書き出すためには非常に長い時間がかかります。それをスピードアップするためにできることはほとんどありません。

あなたが望むのは、I/O時間がプログラムの最大部分であるため、処理速度ではなくハードディスクの速度によって速度が制限されることです。理想は、file.write()が100%使用することです!

+0

+1、通常はあなたに同意します。しかし、この場合、私がデータを生成するために使用している外部プロセスは非常に遅いので、可能な限り他のものはすべて最小限に抑えたい。私は数秒で話して、それを減らすことに集中すべきだと思います。秒数を明確にするために編集します。 – chmullig

+0

1,500レコードを書き込むのに20秒かかることを指定するように更新されました。私はその数を本当に気にしていますが、実際には最適化する価値があることを証明するためにパーセンテージを使用していました。 – chmullig

+0

@chmullig、何%が外部プロセスを待っていますか? –

1

あなたはmmapをPythonで行うことができます。かもしれない助けてください。しかし、私はプロファイリング中にあなたが間違いをしたと思う。なぜなら、20秒間の7k * 1500は約0.5Mbytes/sだからだ。同じ長さのランダムな線を書き込むテストを行います。それよりもはるかに高速です。

関連する問題