5

データのストリームを生成する機器があります。私のコードは callback を介してこのデータにアクセスしますonDataAcquisitionEvent(const InstrumentOutput &data)。データ処理アルゴリズムは、データの到着速度よりも大幅に遅くなる可能性があるため、すべてのデータを処理することは期待できませんが (そうする必要はありません)、できるだけ多くのデータを処理したいと考えています。私が制御できないデータ取得速度を備えた環境センサーとしての機器に感謝します。InstrumentOutputたとえば、異なる場所での 3 つの同時圧力測定値を含むクラスである可能性があります。

また、データの簡単な履歴を保持する必要があります。たとえば、データのサンプルを 200 ミリ秒ごとに処理することが合理的に期待できると仮定します。ほとんどの場合、最後のサンプルを 1 つだけ処理しても問題ありませんが、最後のサンプルに異常な読み取り値が存在するかどうかに応じて、その最新のサンプルの前に到着した数秒分のデータを確認する必要がある場合があります。

onDataAcquisitionEvent()もう 1 つの要件は、センサーでのデータ損失を回避するために、できるだけ早くコールバックから抜け出すことです。

データ取得ライブラリ (サードパーティ) は、別のスレッドで機器データを収集します。

次のデザインを考えました。単一のプロデューサー/単一のコンシューマー キューを持ち、データ トークンを onDataAcquisitionEvent() コールバックの同期キューにプッシュします。
受信側では、キューからデータをポップするループがあります。データ到着率が高いため、ループはほとんどスリープしません。各反復で、次のことが起こります。

  1. 利用可能なすべてのデータをキューからポップし、
  2. ポップされたデータは循環バッファーにコピーされます (ブースト循環バッファーを使用しました)。このようにして、履歴が常に利用可能になります。
  3. バッファ内の最後の要素を処理します (そして、前の要素を調べる可能性があります)。
  4. ループを繰り返します。

質問:

  1. この設計は適切ですか? また、落とし穴は何ですか? と
  2. より良いデザインは何でしょうか?

編集:私が考えた1つの問題は、循環バッファのサイズが必要な履歴を保持するのに十分な大きさではない場合です。現在、単純に循環バッファーを再割り当てして、そのサイズを 2 倍にしています。1回か2回だけでいいと思います。

4

3 に答える 3

3

私はデータ取得の経験が少しありますが、多くの開発者が時期尚早のフィーチャークリープに問題を抱えていると言えます。機器からログにデータをキャプチャするのは簡単に聞こえるので、人々は、ロギングが実際に堅牢であることを確認する前に、システムに不要なコンポーネントを追加する傾向があります。これは大きな間違いです。

onDataAcquisitionEvent()もう1つの要件は、センサーでのデータ損失を回避するために、できるだけ早くコールバックから抜け出すことです。

これは、製品のその部分がすべてのフィールド条件下で110%動作するまでの唯一の要件です。


ほとんどの場合、最後の1つのサンプルだけを処理できれば幸いですが、最後のサンプルに異常な読み取り値が存在するかどうかによっては、最新のサンプルの前に到着した数秒分のデータを確認する必要がある場合があります。

「ほとんどの場合」は関係ありません。onDataAcquisitionEvent()不測の事態について考えることに時間を費やすことができないため、最悪の場合のコード。

利用可能な最高のデータで動作するように設計するという落とし穴に陥っているようです。利用できない場合や、モニターに最高のデータを提供するのに最終的に費用がかかりすぎる場合は、何が起こるかを開いたままにしておきます。

ソースでデータを間引きます。異常なケースの処理に必要なサンプルの数を指定し、一定のサンプルレートに加えて、おそらく20%のマージンでその数を提供しようとします。

決して眠らないループがあってはなりません。循環バッファは問題ありませんが、必要最小限のものを入力し、必要な頻度でのみ分析します。

システムの品質は、その安定性と決定論によって決定されます。余分な距離を移動して、可能な限り多くを提供しようとはしません。

于 2012-07-22T03:18:37.127 に答える
0

質問、(1) このデザイン サウンドとは何か、落とし穴は何か、(2) より良いデザインとは何か。ありがとう。

はい、音です。ただし、パフォーマンス上の理由から、各処理段階で 1 つのサンプルだけではなく、入力サンプルの配列を処理するようにコードを設計する必要があります。これにより、現在の最先端の CPU に最適なコードが得られます。

このような配列 (= データのチャンク) の長さは、固定 (より単純なコード) または可変 (柔軟ですが、一部の処理はより複雑になる場合があります) のいずれかです。

2 番目の設計上の選択肢として、おそらくこのアーキテクチャ レベルでの履歴を無視し、その機能を委譲する必要があります...

ほとんどの場合、最後のサンプルを 1 つだけ処理しても問題ありませんが、数秒分のデータを確認する必要がある場合もあります [...]

おそらく、履歴の追跡は、時々アクセスが必要になるコードの特別な部分に実装する必要があります。たぶん、それは「全体的なアーキテクチャ」の一部であってはなりません。もしそうなら、それは処理をまったく単純化します。

于 2012-07-22T05:25:49.123 に答える
0

あなたの生産者/消費者設計はまさに正しい設計です。リアルタイムシステムでは、多くの場合、消費スレッドに異なる実行時の優先度を与えますが、これがあなたのケースに当てはまるかどうかはわかりません.

基本的に二重にリンクされたリストであるデータ構造を使用して、それが大きくなってもすべてを再割り当てする必要がないようにし、必要なサンプルに O(1) アクセスすることもできます。

メモリが数秒分のデータを保持するのに十分な大きさでない場合 (200 ミリ秒ごとに 1 サンプル? 1 秒あたり 5 サンプル)、補助メモリからの読み取りに耐えられるかどうかを確認する必要がありますが、それはスループットです。あなたの場合、「できるだけ早くコールバックから抜け出す」という設計と要件とは何の関係もありません。

コールバックが停止しないように、ロックを必要としないキューの実装を検討してください (1 つのリーダーと 1 つのライターのみを思い出してください!)。

コールバックが非常に速い場合は、割り込みを無効にする/優先度を高くすることを検討してください。ブロックすることができず、適切な優先順位が設定されている場合は、必要ない場合があります。

于 2012-07-22T04:18:16.780 に答える