データをバイナリングする最良の方法は何ですか
-
25-10-2019 - |
質問
タグ=値として記述されたデータファイルがいくつかあります。タグは文字列、値は数値、文字列、配列などです。読みやすく、簡単に編集できるため、この形式を使用します。この形式を使用してインスタンス化されたすべてのクラスにはロードメソッドがあり、必要なタグを読み取り、これらのタグ内で見つかった値を使用します。読み込み速度を上げるためにデータバイナリを作成したいと思います。 1つの方法は、古いデータを読み取り、ファイルに記述するすべてのクラスにトビナリ(名前は重要ではない)メソッドを使用することです。新しいファイルを使用してオブジェクトをインスタンス化することです。これは、オフラインで実行できます。これについて他の提案はありますか?これにはC ++を使用しています。
編集:最も高価な部分は、最初に読んだときにファイルを解析することであり、その後、ディスクからファイルを読み取らないで、必要なタグを検索することだと思います。カスタムファイルシステムを使用して、1つの大きなファイルに複数の小さなファイルを配置できます。
解決
これのためのシリアル化ベースクラスがあり、バージョンの処理を組み込むことができる小さなヘッダーを備えた関数との間で。地元で保存する必要があるより単純なデータのための優れたシステムであり、ほとんどの場合、「読み取り専用」だと思います。
このようなもの:
class SeralizeMe
{
public:
virtual bool To(Archive &file)=0;
virtual bool From(Archive &file)=0;
virtual bool NeedsSave(void)=0;
};
ただし、次の場合はこのシステムを使用しないでください。
- フォーマットを頻繁に変更する必要があります。
- ロードするデータと保存するデータを選択する必要があります。
- 保存中に停電に敏感なParticulareである大きなファイルを使用します。
上記のいずれかが適用される場合は、データベースを使用して、FireBirdSQLが組み込まれているのは適切な候補です。
他のヒント
私は以前にそれを使用したことがありませんが、私は確信しています Boostのシリアル化モジュール 開始するのに適した場所です。
ファイルを使用している場合、ファイルに保存するための非常に大きなデータがない限り、バイナリデータを使用するとパフォーマンスが大幅に向上しない可能性があります(画像、ビデオ...)。
とにかく、からのバイナリシリアル化アルゴリズムを使用できます。 ブースト.
もう1つはGoogleのProtobufです。最速ではありませんが、進化するデータ型をサポートでき、ネットワークよりも非常に効率的で他の言語をサポートしています。
リンク ここ.
パフォーマンスを改善したい場合は、固定長さフィールドを使用する必要があります。変数の長さフィールドの解析または負荷は、パフォーマンスの大幅な増加を提供しません。テキストラインによる読み取りには、ライントークンの終わりのスキャンが含まれます。廃棄物の時間をスキャンします。
次の提案のいずれかを使用する前に、コードをプロファイリングして、パフォーマンスのベースライン時間または数を確立します。それはあなたが計算できるようにするので、それぞれの提案の後にこれを行います パフォーマンスデルタ 各最適化の。私の予測では、最適化ごとにデルタが小さくなるということです。
最初にファイルを固定長のレコードに変換し、まだテキストを使用することをお勧めします。必要に応じてスペースのあるパッドフィールド。したがって、レコードのサイズを知ると、メモリに読み取りをブロックし、メモリを配列として扱うことができます。これは大幅な改善を提供するはずです。
この時点で、ボトルネックはまだファイルI/O速度であり、実際に大幅に改善することはできません(ファイルI/OはOSによって制御されているため)、テキストをスキャン/変換します。さらに最適化は次のとおりです。テキストを数値に変換し、最終的にバイナリに変換します。 いずれにせよ、データファイルを人間の読み取り可能な形式に保持することを好みます。
データファイルを読み取りの少ない前に、アプリケーションをスレッドに分割してみてください。 1つのスレッドはGUIを処理し、もう1つは入力を処理し、もう1つは処理用に処理します。アイデアにはプロセッサがあります いつも 待機するのではなく、コードの一部を実行します。最新のプラットフォームでは、CPUがコードを処理している間にファイルI/Oを実行できます。
移植性が気にしない場合は、プラットフォームにDMA機能があるかどうかを確認します(DMAまたはダイレクトメモリアクセスコンポーネントにより、プロセッサを使用せず、プロセッサの使用を最小限に抑えることなくデータ転送が可能になります)。注意すべきことは、多くのプラットフォームがプロセッサとDMAの間でアドレスとデータバスを共有していることです。したがって、1つのコンポーネントはブロックされるか、中断され、もう1つはアドレスバスとデータバスを使用します。だからそれは助けになるかどうか。プラットフォームの配線方法によって異なります。
キーフィールドを使用して数字を使用して変換します トークン. 。トークンは数値であるため、ジャンプテーブル(スイッチステートメント)へのインデックスとして使用するか、アレイへのインデックスのみを使用できます。
最後の手段として、ファイルをバイナリに変換します。バイナリバージョンには、キーとしてのキーと値の2つのフィールドが必要です。大きなチャンクでデータをメモリに移動します。
概要
- 大きなデータブロックをメモリに持ちます。
- 変更する前にプロファイルベースラインパフォーマンス測定を確立します。
- 一度に1つのステップを最適化し、各最適化の後にプロファイリングします。
- データファイルを人間の読み取り可能な形式に保持することを好みます。
- データファイルの変更を最小限に抑えます。
- ファイルを変換して固定長フィールドを使用します。
- アプリケーションが待たないように、スレッドやマルチタスクを使用してみてください。
- テキストを数値トークンに変換する(人間の読みやすさを減らす)
- データを最後の手段としてバイナリに変換します(人間が読んでデバッグするのは非常に困難です)。
私はあなたのために2つのアイデアを持っています:
1)タグのリストが一定であり、事前に既知の場合、それぞれをバイト(または単語)に変換することができ、その後に値の長さ(バイト単位)が続き、その後に値の生のcストリングが続くことができます。ペイロード。
たとえば、以下を考慮してください。
Tag1 = "hello World!" // 12 bytes in length (achieved by "strlen(value) * sizeof(char)" )
Tag2 = "hello canada!" // 13 bytes in length
これをバイトストリームに変えることができます:
0x0001 0x000B // followed by 12 bytes representing the 'value' // 0x0002 0x000C // followed by 13 bytes representing 'value2'
プログラムは、ヘッダーという単語「0x0001」がTag1を表し、ヘッダー「0x0002」がTag2を表すことを知る必要があります。
同様の長さ、値構造に従うことにより、事前にそれらを知らない場合、さらにタグ名をさらに抽象化することができます。
2)おそらく遅いビットは、テキスト解析の実装だけですか?専用のオープンソースライブラリを使用して、やろうとしていることを検討してください。例: "Boost :: Property_tree"
プロパティツリーは、キー値ペア(構成設定ファイルとして使用するために設計されている)を保存および取得するように特別に設計されています。しかし、これが経済的になるためにあなたが保存しようとしているそのようなペアの数に依存すると思います。