2

I'm using python to set up a computationally intense simulation, then running it in a custom built C-extension and finally processing the results in python. During the simulation, I want to store a fixed-length number of floats (C doubles converted to PyFloatObjects) representing my variables at every time step, but I don't know how many time steps there will be in advance. Once the simulation is done, I need to pass back the results to python in a form where the data logged for each individual variable is available as a list-like object (for example a (wrapper around a) continuous array, piece-wise continuous array or column in a matrix with a fixed stride).

At the moment I'm creating a dictionary mapping the name of each variable to a list containing PyFloatObject objects. This format is perfect for working with in the post-processing stage but I have a feeling the creation stage could be a lot faster.

Time is quite crucial since the simulation is a computationally heavy task already. I expect that a combination of A. buying lots of memory and B. setting up your experiment wisely will allow the entire log to fit in the RAM. However, with my current dict-of-lists solution keeping every variable's log in a continuous section of memory would require a lot of copying and overhead.

My question is: What is a clever, low-level way of quickly logging gigabytes of doubles in memory with minimal space/time overhead, that still translates to a neat python data structure?


Clarification: when I say "logging", I mean storing until after the simulation. Once that's done a post-processing phase begins and in most cases I'll only store the resulting graphs. So I don't actually need to store the numbers on disk.


Update: In the end, I changed my approach a little and added the log (as a dict mapping variable names to sequence types) to the function parameters. This allows you to pass in objects such as lists or array.arrays or anything that has an append method. This adds a little time overhead because I'm using the PyObject_CallMethodObjArgs function to call the Append method instead of PyList_Append or similar. Using arrays allows you to reduce the memory load, which appears to be the best I can do short of writing my own expanding storage type. Thanks everyone!

4

2 に答える 2

2

C 拡張モジュールとしてではなく、Cython でこれを行うことを検討することをお勧めします。Cython はスマートで、C データ型と Python データ型を同時に使用できるにもかかわらず、非常に Pythonic な方法で物事を行うことができます。

配列モジュールをチェックアウトしましたか? 単一のコレクションに多数の同種のスカラー型を格納できます。

これらを CPython に返すだけでなく、本当に「ログに記録」している場合は、ファイルを開いて fprintf してみてください。

ところで、C 拡張モジュールを使用するか Cython を使用するかに関係なく、ここでは realloc が役に立ちます。

于 2012-08-16T20:42:31.907 に答える
1

これは、一貫した答えというよりも、アイデアの膨大なダンプになるでしょう。それがあなたが探しているもののように聞こえるからです。そうでない場合は、お詫び申し上げます。

ここで避けようとしている主なことは、何十億ものPyFloatObjectsをメモリに保存することです。それを回避する方法はいくつかありますが、それらはすべて、代わりに数十億のプレーンCダブルを格納し、それらをPyFloatObjectsのシーケンスであるかのようにPythonに公開する方法を見つけることに重点を置いています。

Python(または他の誰かのモジュール)に作業を行わせるには、numpy配列、標準ライブラリ配列、structモジュールの上にある単純な手作りラッパー、またはctypesを使用できます。(拡張モジュールを処理するためにctypesを使用するのは少し奇妙ですが、それを妨げるものは何もありません。)structまたはctypesを使用している場合は、巨大なファイルを作成してメモリの制限を超えることもできます。必要に応じてウィンドウにマッピングします。

Cモジュールに作業を行わせるには、実際にリストを返すのではなく、シーケンスプロトコルを満たすカスタムオブジェクトを返します。そのため、誰かがfooを呼び出した場合などです。getitem(i)_array[i]をその場でPyFloatObjectに変換します。

mmapのもう1つの利点は、配列を繰り返し作成する場合、ファイルにストリーミングするだけで配列を作成し、結果のファイルをメモリのブロックとしてmmapして戻すことで配列を使用できることです。

それ以外の場合は、割り当てを処理する必要があります。標準アレイを使用している場合は、必要に応じて自動拡張を処理しますが、それ以外の場合は、自分で実行します。再割り当てを実行し、必要に応じてコピーするコードはそれほど難しくなく、オンラインには多くのサンプルコードがありますが、それを作成する必要があります。または、Pythonに公開できるストライドコンテナを、連続していない場合でも連続しているかのように構築することを検討することもできます。(これは複雑なバッファープロトコルを介して直接行うことができますが、個人的には、独自のシーケンス実装を作成するよりも難しいことが常にわかっています。)C ++を使用できる場合、vectorは自動拡張配列であり、dequeはストライドコンテナです(また、SGI STLロープを使用している場合は、実行している種類の作業に適したストライドコンテナになる可能性があります)。

他の回答が指摘しているように、Cythonはこれのいくつかを助けることができます。「Pythonにたくさんのfloatを公開する」部分はそれほど多くありません。Pythonパーツの一部をCythonに移動すると、Cにコンパイルされます。運が良ければ、多くのfloatを処理する必要のあるすべてのコードは、Cythonが実装するPythonのサブセット内で機能します。 、そして実際に解釈されるコードに公開する必要があるのは、高レベルのドライバー(それでも)だけです。

于 2012-08-16T21:42:11.807 に答える