3

数値データのみを保持するレコードをフォーマット文字列で固定に変換し、Python でファイルに書き込む最速の方法は何ですか? たとえば、が、、 、、 のrecord属性を持つオブジェクトで構成される巨大なリストであり、頻繁にそれらを外部ファイルにフラッシュする必要があるとします。フラッシュは、次のスニペットで実行できます。idxywt

with open(serial_fname(), "w") as f: 
    for r in records:
        f.write("%07d %11.5e %11.5e %7.5f\n" % (r.id, r.x, r.y, r.wt))

ただし、私のコードは外部ファイルの生成に多くの時間を費やしており、フラッシュ間で行うべきことを行う時間が少なすぎます。

元の質問を修正します。

複数の「プロデューサー」システムから情報を取得してグローバル レコード セットを追跡し、レコード セットへの変更をリアルタイムまたはほぼリアルタイムで「コンシューマー」システムに中継するサーバー ソフトウェアを作成しているときに、この問題に遭遇しました。前処理された形で。コンシューマ システムの多くは Matlab アプリケーションです。

これまでに受け取ったいくつかの提案を以下にリストします(感謝します)。いくつかのコメントがあります。

  • データセット全体ではなく、変更のみをダンプします:私は実際にこれを既に行っています。結果の変更セットは依然として巨大です。
  • バイナリ (または他のより効率的な) ファイル形式を使用します。Matlab が合理的に効率的に読み取ることができるものにかなり制約があり、それに加えて、形式はプラットフォームに依存しない必要があります。
  • データベースを使用する:私は実際、特に Matlab 側では遅すぎて扱いにくいと見なされている現在のデータベース ソリューションをバイパスしようとしています。
  • タスクを個別のプロセスに分割:現時点では、ダンプ コードは独自のスレッドで実行されています。ただし、GIL のため、同じコアを消費しています。完全に別のプロセスに移動できると思います。
4

5 に答える 5

3

numpy.savetxtが少し高速化できるかどうかを確認しようとしていたので、次のシミュレーションを作成しました。

import sys
import numpy as np

fmt = '%7.0f %11.5e %11.5e %7.5f'
records = 10000

np.random.seed(1234)
aray = np.random.rand(records, 4)

def writ(f, aray=aray, fmt=fmt):
  fw = f.write
  for row in aray:
    fw(fmt % tuple(row))

def prin(f, aray=aray, fmt=fmt):
  for row in aray:
    print>>f, fmt % tuple(row)

def stxt(f, aray=aray, fmt=fmt):
  np.savetxt(f, aray, fmt)

nul = open('/dev/null', 'w')
def tonul(func, nul=nul):
  func(nul)

def main():
  print 'looping:'
  loop(sys.stdout, aray)
  print 'savetxt:'
  savetxt(sys.stdout, aray)

結果は(私の 2.4 GHz Core Duo Macbook Pro、Mac OS X 10.5.8、python.org の DMG からの Python 2.5.4、ソースからビルドされた numpy 1.4 rc1 で)少し驚くべきものでしたが、かなり再現可能です。だから私は彼らが興味があるかもしれないと思った:

$ py25 -mtimeit -s'import ft' 'ft.tonul(ft.writ)'
10 loops, best of 3: 101 msec per loop
$ py25 -mtimeit -s'import ft' 'ft.tonul(ft.prin)'
10 loops, best of 3: 98.3 msec per loop
$ py25 -mtimeit -s'import ft' 'ft.tonul(ft.stxt)'
10 loops, best of 3: 104 msec per loop

そのため、savetxt はループ呼び出しよりも数パーセント遅いwriteようです...しかし、古き良き(ループ内でも)よりもprint数パーセント速いwriteようです(ある種の呼び出しオーバーヘッドを回避していると思います)。2.5%程度の差は大したことないとは思いますが、直感的に思ったほどではなかったので、報告しようと思います。(ところで、/dev/null均一に 6 ミリ秒または 7 ミリ秒を追加するだけでなく、実際のファイルを使用すると、何らかの形で物事が大きく変わることはありません)。

于 2009-12-06T19:26:55.140 に答える
2

あなたのコードスニペットについて、私が本当に最適化できるものは何も見当たりません。ですから、あなたの問題を解決するには、まったく違うことをする必要があると思います。

あなたの問題は、あなたが大量のデータを噛んでいることであるように思われ、データを文字列にフォーマットして文字列をファイルに書き込むのが遅いです。あなたは「フラッシュ」と言いましたが、これはデータを定期的に保存する必要があることを意味します。

すべてのデータを定期的に保存していますか、それとも変更されたデータだけを保存していますか?非常に大きなデータセットを処理し、一部のデータのみを変更し、すべてのデータを書き込む場合...これは、問題を解決するために攻撃できる角度です。

大規模なデータセットがあり、それを時々更新したい場合...あなたはデータベースの候補です。速度を上げるためにCで記述された実際のデータベースを使用すると、大量のデータ更新をスローでき、すべてのレコードを一貫した状態に保つことができます。次に、定期的に「レポート」を実行して、レコードをプルし、そこから固定幅のテキストファイルを書き込むことができます。

言い換えれば、問題を2つの部分に分割することを提案しています。データを計算または受信するときにデータセットを少しずつ更新することと、データセット全体を固定幅のテキスト形式にダンプしてさらに処理することです。

更新中のPythonプロセスを停止せずに、データベースからテキストファイルを実際に生成できることに注意してください。不完全なスナップショットが得られますが、レコードが独立している場合は問題ありません。

さらに処理をPythonで行う場合は、データをデータベースに永久に残すことができます。固定幅のテキストファイルを介してデータをラウンドトリップする必要はありません。将来の処理のためにデータを再度抽出するのは簡単なので、固定幅のテキストファイルを使用していると想定しています。

データベースのアイデアを使用する場合は、PostgreSQLを使用してみてください。それは無料で、実際のデータベースです。Pythonでデータベースを使用するには、ORMを使用する必要があります。最高の1つはSqlAlchemyです。

考慮すべきもう1つのこと:将来の解析と別のアプリケーションでのデータの使用のためにデータを固定幅のテキストファイル形式で保存し、そのアプリケーションが固定幅だけでなくJSONも読み取ることができる場合は、 JSONを書き込むCモジュール。これ以上速くはないかもしれませんが、そうかもしれません。あなたはそれをベンチマークして見ることができます。

上記以外の私の唯一のアイデアは、プログラムを「ワーカー」部分と「アップデーター」部分に分割することです。ここで、ワーカーは更新されたレコードを生成し、アップデーター部分はレコードをディスクに保存します。おそらく、ワーカーに更新されたレコードをテキスト形式で標準出力に配置させることで、コミュニケーションをとらせます。そして、アップデーターに標準入力から読み取らせ、データのレコードを更新させます。SQLデータベースの代わりに、アップデーターは辞書を使用してテキストレコードを格納できます。新しいものが到着すると、辞書を更新するだけで済みます。このようなもの:

for line in sys.stdin:
    id = line[:7]  # fixed width: id is 7 wide
    records[id] = line # will insert or update as needed

実際には、アップデーターに2つの辞書を保持させ、一方を更新し続け、もう一方をディスクに書き出すことができます。

ワーカーとアップデーターに分割することは、ワーカーが更新にすべての時間を費やさないようにするための優れた方法であり、複数のCPUコア間で作業のバランスを取るための優れた方法です。

私は今のところアイデアがありません。

于 2009-12-06T09:26:50.513 に答える
0

あなたがあなたの質問を更新したので、私はあなたが直面していることについて少し良い考えを持っています。

「遅すぎて面倒だと思われる現在のデータベースソリューション」が何であるかはわかりませんが、正しく使用すればデータベースが役立つと思います。

Pythonコードを実行してデータを収集し、ORMモジュールを使用してデータをデータベースに挿入/更新します。次に、別のプロセスを実行して、固定幅のテキストファイルである「レポート」を作成します。データベースは、テキストファイルを生成するすべての作業を実行します。最近のハードウェアはかなり安いので、必要に応じて、データベースを独自のサーバーに配置します。

于 2009-12-06T19:21:42.453 に答える
0

長い文字列を使用するなど、メモリ内のすべての出力文字列の作成を試みることができます。次に、この長い文字列をファイルに書き込みます。

より高速:情報のログ記録には、テキストファイルではなくバイナリファイルを使用することをお勧めします。ただし、バイナリファイルを表示するには別のツールを作成する必要があります。

于 2009-12-06T08:29:03.593 に答える
0

ctypes を使用してループを C にプッシュしようとすることができます。

于 2009-12-06T19:36:29.193 に答える