VIの実行速度



LabVIEW 2018ヘルプ


発行年月: 2018年3月
製品番号: 371361R-0112
製品情報を参照

ダウンロード (Windowsのみ)


LabVIEW 2015ヘルプ
LabVIEW 2016ヘルプ
LabVIEW 2017ヘルプ
LabVIEW 2018ヘルプ
LabVIEW 2019ヘルプ

LabVIEWはVIをコンパイルして、通常、高速で実行するコードを生成しますが、タイムクリティカルなVIで作業している場合は、VIの最高のパフォーマンスを得ることが必要です。このセクションでは、実行速度に影響する要素を説明し、最大のパフォーマンスを得るプログラミングテクニックについて紹介します。

パフォーマンスが遅い原因を特定するため、次の項目を調べてください。

  • 入力/出力(ファイル、GPIB、データ集録、ネットワーク)
  • 画面表示(制御器が大きい、制御器が重なっている、表示器の数が多すぎる)
  • メモリ管理(配列および文字列の非効率的な使用、非効率的なデータ構造)
  • コンパイラ最適化(コンパイラが選択するエディタ応答性とVI実行速度とのバランス)

実行オーバーヘッドやサブVI呼び出しのオーバーヘッドなど、その他の要素は通常実行速度に影響しません。

入力/出力

通常、入力/出力(I/O)の呼び出しには、オーバーヘッドが大きくなります。多くの場合、I/Oの呼び出しには計算処理よりも時間がかかります。たとえば、単一のシリアルポートの読み取り操作には、数ミリ秒の関連オーバーヘッドが発生することがあります。このオーバーヘッドは、I/Oの呼び出しがオペレーティングシステムの複数の階層を介した情報転送を伴うため、シリアルポートを使用する任意のアプリケーションで発生します。

大きなオーバーヘッドの問題を解決するには、I/O呼び出しの回数を最低限に抑えるのが最も良い方法です。そのようにVIを構成することができれば、少ないデータ量を転送する複数のI/O呼び出しを作成する代わりに、各呼び出しで相当量のデータを転送することができるので、パフォーマンスが向上します。

たとえば、データ集録(NI-DAQmx)VIを作成する場合は、データの読み取りに2つのオプションがあります。「AIチャンネルサンプル」VIなどのシングルポイントデータ転送の関数を使用するか、または「AIチャンネル波形集録」VIなどのマルチポイントデータ転送の関数を使用することができます。100ポイントを集録する必要がある場合は、タイミングを確立するために「待機」関数とループで「AIチャンネルサンプル」VIを使用してください。また、100ポイントが必要であることを示す入力とともに「AIチャンネル波形集録」VIを使用することもできます。

「AIチャンネル波形集録」VIはハードウェアタイマを使用してデータのサンプリングを管理するため、「AIチャンネル波形集録」VIを使用すると、より高度で正確なデータのサンプルレートを作成することができます。さらに、より多くのデータを転送しますが、「AIチャンネル波形集録」VIのオーバーヘッドは「AIチャンネルサンプル」VIの単一の呼び出しにかかるオーバーヘッドとほぼ同じです。

画面表示

頻繁にフロントパネルで制御器を更新する操作は、アプリケーションで最も時間がかかる操作のうちの1つとなる場合があります。これは、特にグラフやチャートなどのより複雑な表示の一部を使用する場合に当てはまります。ほとんどの表示器は古いデータと同じ新規のデータを受信する際再描画されませんが、グラフとチャートは必ず再描画されます。再描画レートが問題になる場合、最良の解決方法はフロントパネルのオブジェクトの数を減らして、フロントパネルの表示をできる限りシンプルにします。グラフおよびチャートの場合、自動スケール、スケールマーカ、アンチエイリアスライン、グリッドをオフにして、表示速度を上げることができます。

その他のタイプのI/Oと同様に、制御器の表示には定量のオーバーヘッドがあります。チャートなどの制御器を使用して、一度に複数のポイントを表示器に渡すことができます。チャートの更新数は、一度にチャートにより多くのデータを渡すことで、チャートの更新数を最小限にすることができます。チャートデータを配列に収集して一度に複数のポイントを表示する場合、データの表示レートが大きく向上します。

実行時にフロントパネルが閉じられているサブVIを設計する場合、表示のオーバヘッドを考慮する必要はありません。フロントパネルが閉じている場合、制御器の描画オーバーヘッドはないため、グラフは配列よりも非効率的です。

マルチスレッドシステムでは、上級→同期表示のショートカットメニュー項目を使用して、制御器および表示器の更新を保留するかどうかを設定できます。デフォルトでは、制御器および表示器は非同期表示を使用します。これは、実行システムがフロントパネルの制御器および表示器にデータを渡した後直ちに実行を続行できることを意味します。その後、ユーザインタフェースシステムは制御器または表示器が更新される必要があることを認識して、新規データを表示するために再描画されます。実行システムが制御器の更新を急速に連続して試みる場合、一部の途中の更新は参照されない可能性があります。

ほとんどのアプリケーションでは、非同期表示によって、ユーザへの表示に影響せずに実行速度が大幅に向上されます。たとえば、人間の目で識別が可能な更新回数よりも多い、1秒間に数百回の割り合いでブール値を更新できます。非同期表示では、ユーザインタフェースのスレッドによって自動的に更新がより遅いレートにされる状態で、実行システムがVIの実行により時間をかけることが可能です。

同期表示にする場合は、制御器または表示器を右クリックして、ショートカットメニューから上級→同期表示を選択し、メニュー項目の横にチェックマークを付けます。

メモ  すべてのデータ値を表示する必要がある場合のみ、同期表示をオンにしてください。同期表示を利用すると、マルチスレッドシステムではパフォーマンスに大きく影響します。

フロントパネルの更新に関するすべての新規要求を保留にするには、パネルアップデートを延期プロパティを使用することもできます。

また、設定およびフロントパネルに配置する制御器を監視することによっても、VIのパフォーマンスを向上させることができます。モニタのカラー深度と分解能をより低くし、モニタのハードウェアアクセラレーションを有効にします。ハードウェアアクセラレーションの詳細については、使用するオペレーティングシステムのドキュメントを参照してください。モダンパレットの制御器の代わりに、クラシックパレットから制御器を使用することでも、VIのパフォーマンスは向上されます。

メモリ管理

VIのメモリを管理して最適実行速度を実現するために、以下の点に留意してください。

コンパイラ最適化

大きなVIでのエディタ応答性を向上させるために、LabVIEWコンパイラはこれらのVIの実行速度を向上させる最適化を制限します。大きなVIの開発が終了したら、LabVIEWがエディタ応答性よりも実行速度を優先するように構成することができます。また、コンパイラ最適化のフルセットをビルド仕様全体に適用するようにLabVIEWを構成することもできます。

アプリケーション内でデータを渡す

LabVIEWアプリケーション内でデータを渡すには、以下に示す多くの方法から選択できます。以下のリストは、最も一般的な方法を効率性の順に示しています。

  1. ワイヤワイヤを使用してデータを渡して、LabVIEWがパフォーマンスの最適化を制御できるようにします。データには1つの書き込みと1つまたは複数の読み取りがあるため、データフローのプログラミング言語ではこれ以上に高速な方法はありません。
  2. フィードバックノードフィードバックノードを使用して、前回のVIまたはループの実行からのデータを保存します。サブVI、関数、あるいはサブVIと関数のグループの出力を同じVI、関数、またはグループの入力に配線し、オプションダイアログボックスのブロックダイアグラムページの帰還ワイヤ内にフィードバックノードを自動的に挿入を有効にする際、フィードバックノードは自動的に表示されます。帰還ワイヤ内にフィードバックノードを自動的に挿入はデフォルトで有効に設定されます。フィードバックノードは最後に実行したVI、関数、またはグループからのデータを保持し、初期化端子を移動するかにより、そのデータが次の実行に渡されるか、または新規の初期値が設定されます。ループでは、フィードバックノードの場合と同じ方法でシフトレジスタでデータが保持されますが、ループに通じるワイヤが必要となります。
  3. シフトレジスタ―ループの内側にストレージまたはフィードバックが必要な場合はシフトレジスタを使用します。シフトレジスタは、1つの外部の書き込みと読み取り、および1つの内部の書き込みと読み取りを介してデータを渡します。このデータアクセスの緊密な有効範囲によって、LabVIEWの効率性が最適化されます。シフトレジスタをフィードバックノードで置換して、ループに通じるワイヤなしで同じ機能を達成します。
  4. グローバル変数および機能的グローバル変数―簡易データおよび簡易アクセスにはグローバル変数を使用します。大きなデータまたは複雑なデータの場合、グローバル変数はすべてのデータを読み取り渡します。機能的グローバル変数を使用してLabVIEWが返すデータ量を制御します。

変数として制御器、制御器リファレンス、プロパティノードを使用する

制御器、制御器リファレンス、プロパティノードを使用してVI間でデータを渡すことはできますが、これらはユーザインタフェースを介して動作するため変数として使用する目的で設計されていません。ユーザインタフェース動作を実行する場合または並列ループを停止する場合にのみ、ローカル変数および値プロパティを使用してください。

ユーザインタフェースの動作は、元来コンピュータ上では低速となります。LabVIEWはワイヤを介して倍精度数の値を渡し、数百マイクロ秒からミリ秒のレートで1つのテキストを描画します。たとえば、LabVIEWは0ナノ秒から2、3マイクロ秒間にワイヤを介して100,000個の配列を渡すことができます。この100,000個の配列のグラフを描画する操作は数十ミリ秒かかります。制御器はユーザインタフェースであるため、制御器を使用してデータを渡すと制御器の再描画が必要となり、メモリの消費が増え、パフォーマンスが低下します。制御器が非表示の場合はデータの受け渡しが高速になりますが、制御器の表示は随時可能であるため、制御器の更新は必要となります。

マルチスレッドがユーザインタフェース動作に与える影響

LabVIEWは実行スレッドからユーザインタフェーススレッドへ切り替えるため、ユーザインタフェースの動作を完了する操作はより多くのメモリを消費します。たとえば、値プロパティを設定する場合、LabVIEWはユーザが制御器の値を変更する、実行スレッドを停止する、およびユーザインタフェーススレッドを切り替えて値を変更する操作をシミュレートします。フロントパネルが開いている場合は、続いて制御器のデータを格納している操作バッファが更新され、制御器が再描画されます。その後、LabVIEWは転送バッファと呼ばれるメモリの保護領域にある実行スレッドにデータを送信し直します。次に、LabVIEWは実行スレッドに切り替えます。次回実行スレッドが制御器のデータを読み取ると、LabVIEWは転送バッファのデータを検出し、ブロックダイアグラムのデータを保存する実行バッファの新しい値を受け取ります。

ローカルまたはグローバル変数に書き込みを行う場合、LabVIEWにすぐにユーザインタフェーススレッドに切り替えません。その代わりに転送バッファに値を書き込みます。ユーザインタフェースは次の更新時に更新されます。変数は、シングルスレッドの切り替えまたはユーザインタフェースの更新が行われる前に複数回更新できます。これは、変数は実行スレッドでのみ動作するからです。

機能的グローバル変数は転送バッファを使用しないため、標準のグローバル変数よりも効率的です。機能的グローバル変数は、開かれているフロントパネルで値を表示しない限り、実行スレッド内にのみ存在し、転送バッファを使用しません。

並行したブロックダイアグラム

並行して実行される複数のブロックダイアグラムがある場合、実行システムはブロックダイアグラム間を定期的に切り替えます。これらのループの一部が他のループよりも重要でない場合、「待機(ms)」関数を使用して、重要でないループによって消費される時間がより少ないことを確実にします。

たとえば、以下のブロックダイアグラムがあるとします。

並行して2つのループがあります。ループの1つはデータを集録中で、可能な限り頻繁に実行する必要があります。もう1つのループはユーザ入力を監視しています。このプログラムの構造では、ループは同じ回数受信します。ユーザの動作を監視するループは、1秒間に数回のレートで実行できます。

現実的に通常ボタンを監視するループが0.5秒以下のレートで実行する場合に適しています。ユーザインタフェースのループで「待機(ms)」関数を呼び出すことで、他のループにより多くの回数を割り当てます。

並列Forループ反復

Forループを使用する際に、LabVIEWはループ反復を順番に実行します。Forループ内の計算が複雑な場合は、ループ反復を並列実行するとパフォーマンスが向上します。並列ループ反復を実行すると、複数のプロセッサの使用によってForループを高速に実行できます。ただし、並列ループ反復は、他の反復とは独立している必要があります。並列実行が可能なForループは、並列化可能なループの検索結果ダイアログボックスで確認できます。並列ループ反復を有効にするには、Forループの境界を右クリックし、ショートカットメニューから反復の並列化を構成を選択してForループ反復並列化ダイアログボックスを開きます。

並列ループ反復を有効にすると、並列インスタンス端子がカウント端子の下に表示されます。この端子は、使用するループインスタンスの数を指定したり、特定の反復を実行するインスタンスを識別したりする場合に使用できます。

Forループの並列実行を有効にする前に、パフォーマンスに関する注意事項を確認してください。

ナショナルインスツルメンツは、並列ループ反復によってVIに問題が生じる可能性がある場合にLabVIEWが警告できるように、エラーリストウィンドウに警告を表示することを推奨します。

サブVIのオーバーヘッド

サブVIを呼び出すと、その呼び出しに関連する一定量のオーバーヘッドが発生します。このオーバーヘッドは、ミリ秒から数十ミリ秒の範囲になり得るI/Oオーバーヘッドと表示オーバーヘッドよりも非常に小さく(約数十マイクロ秒)なります。ただし、場合によっては、このオーバーヘッドは蓄積されます。たとえば、ループでサブVIを10,000回呼び出す場合、このオーバーヘッドは実行スピードに大きく影響します。この場合、サブVIにループを埋め込むことを考慮するとよい場合があります。

サブVIのオーバーヘッドはVIプロパティダイアログボックスのカテゴリプルダウンメニューから実行を選択し、優先度プルダウンメニューからサブルーチンを選択して、サブVIをサブルーチンに変換することで、最小化することもできます。ただし、この操作による悪影響もあります。サブルーチンは、フロントパネルのデータの表示、タイミングまたはダイアログボックス関数の呼び出し、デバッグまたは自動エラー処理、または他のVIとのマルチタスクを行うことができません。通常、サブルーチンは、ユーザとの操作を必要としない、短く頻繁に実行されるタスクのVIに最も適しています。

さらに、サブVIを発呼者VIにインライン化してサブVIのオーバーヘッドを最小化する方法もあります。サブVIをインライン化すると、サブVIのコンパイルコードが発呼者VIのコンパイルコードに挿入されます。サブVIを変更すると、そのサブVIのすべての発呼者VIが変更内容を反映させるために再コンパイルされます。サブVIをインライン化すると、実行時にサブVIを呼び出す必要がなくなります。サブVIが呼び出される代わりに、発呼者VIのコンパイルコード内部のサブVIコードが実行されます。

インライン化は、小さなサブVIや、ループ内のサブVI、未配線の出力を持つサブVI、1回だけ呼び出されるサブVIで使用すると最も有効です。サブVIをインライン化するには、VIプロパティダイアログボックスの実行ページでサブVIを発呼者VIにインラインチェックボックスをオンにします。ダイアログボックスの同じページでクローンの事前割り当てによる再入実行も選択する必要があります。サブVIがインライン化されると、各インスタンスにクローンが事前に割り当てられます。

以下のいずれかの特性を有するサブVIはインライン化できません。

  • 再帰動作がある。
  • 自動エラー処理を使用する。
  • 特定のブロックダイアグラムノード(プロパティノードおよびインボークノードなど)を使用する。サブVIのインライン化を有効にすると、これらのノードは編集時エラーメッセージを生成します。
  • デバッグを許可する。インライン化するサブVIでは、デバッグを無効にする必要があります。
  • 以下のいずれかのタイプのVIである。
    • LabVIEWクラスのダイナミックディスパッチVI
    • CGenまたはFPGAをターゲットとしている
    • 制御器VI ― カスタム制御器または表示器を定義するVI
    • 多態性VI
    • グローバル変数VI
    • XControl VI
    • XControlライブラリのメソッドVI
    • LabVIEW Control Design and Simulation(制御系設計/シミュレーション)モジュールのシミュレーションダイアグラムにのみ配置可能なVI

サブVIに上記の特性がない場合でも、サブVIは以下のタイプの呼び出しにはインライン化されません。

また、サブVIをインライン化すると、優先度または優先実行に関する設定がすべて無視されます。

サブVIをインライン化してパフォーマンスを向上させるサンプルについては、examples\Performance\VI PropertiesにあるVI Execution Properties VIを参照してください。

シェア変数のオーバーヘッド

ネットワーク共有シェア変数を使用すると、CPUとメモリのオーバーヘッドが大幅に増加します。開発したアプリケーションでネットワーク共有シェア変数が多用されている場合は、シンプルメッセージングリファレンスライブラリ(STM)で代用することを検討してください。STMの詳細については、ni.comサポートドキュメントを参照してください。

2つの演算デバイス間での連続的なデータストリーミングが必要な場合は、ネットワークストリーム関数を使用します。

ループでの不要な数値演算

計算によって各反復で同じ値が生成される場合、ループに演算を配置しないでください。その代わりに、演算をループの外側に移動して、その結果をループに渡します。

たとえば、以下のブロックダイアグラムがあるとします。

ループの各反復での除算の結果は同じなため、以下のブロックダイアグラムに示すように、除算をループの外側に移動することでパフォーマンスを向上できます。

以下のブロックダイアグラムを参照してください。

このループの実行中にグローバル変数の値が別の同時に実行されているブロックダイアグラムまたはVIによって変更されないことが確実な場合、このブロックダイアグラムでは各ループの反復でグローバル変数からの読み取りとグローバル変数への書き込みによって時間が消費されます。

このループの実行中に別のブロックダイアグラムによって読み取りまたは書き込みされるグローバル変数が必要でない場合、代わりに以下のブロックダイアグラムを使用するとよい場合があります。

シフトレジスタは、サブVIからループの次の反復に新規値を渡す必要があることに注意してください。以下のブロックダイアグラムは、初心者ユーザにありがちな一般的なエラーを示します。シフトレジスタがないため、サブVIからの結果は決して新規の入力値としてサブVIに返されません。



この記事は役に立ちましたか。

役に立たなかった