前章の「制限値」に記載された値以下での使用であってもCPUやGUIエンジンに負荷がかかってしまうことがあります。
本章では特にGUIエンジン(Tcl/Tk)の高負荷を避けるための配慮について解説します。
MindのGUIプログラムでウィジェットや図形が描画される仕組みは次の図のようになります。
・−GUIプログラム(Mind記述) −−・
| |
| |
| 描画をおこなう処理 |
| |||| |
・−−−−−−−↓↓↓↓−−−−−・
||||
・−GUIエンジン ||||−−−−−・
| ↓↓↓↓ |
| (コマンド・キューへ格納) |
| |
| (コマンド・キューから取出) |
| ↓↓↓↓ |
| レンダリング処理 |
| |||| |
・−−−−−−−||||−−−−−・
||||
・−Windows OS ↓↓↓↓−−−−−・
| 物理的なグラフィック描画 |
| |
| |
・−−−−−−−−−−−−−−−−・
上記を説明します。
MindのGUIアプリケーションが何らかの描画をおこなう単語を実行すると、GUIエンジン(Tcl/Tk)に対するコマンド群に変換され、GUIエンジン内部のコマンド・キューに格納されます。格納すると直ちに戻って来る(実際に描画されるまで待たない)ため、Mind側としてはすぐ次の描画処理をおこなうことができます。
一方、GUIエンジンの側では、コマンド・キューに何かのコマンドが投入されたのを検出するとそれを解読・実行します。GUIエンジンはさらにWindowsのAPIに処理をゆだね、そちらで最終的な描画をおこないます。これはコマンド・キューが空になるまで続けます。
Mindのプログラムと、GUIエンジンは並行して実行されるのですが、厳密には本当の並行ではなく、CPU時間を両者で分け合う形となります。
Mindのプログラムは(たとえばイベント処理の処理単語が起動されたら)一旦走り出したらフルパワーで走行し処理単語の終りまで来るとイベント処理の終りとなり、GUIエンジンに制御を戻します。
一方、GUIエンジンの処理はプログラム全体としての"アイドルタイム"(Mindが走行していない時)にのみ処理時間が振り分けられるため、常にフルパワーで走れるわけではありません。
この両者の違いのためにどのようなことが起きるかと言うと、Mindが次から次へと描画処理を実行し、それを長時間に渡って続けた場合、前記した「描画される仕組み」の図で言う「コマンド・キュー」が満杯になる可能性があるとういうことです。コマンド・キューへの投入に対して、その取り出し側が追い付かないことになります。
■原因
コマンド・キューが満杯になる現象はよく起きるわけではありません。
たとえば、ウィンドウにボタンやラベルなど
多量のウィジェットを配置して埋め尽くすことは現実のアプリケーションとしてはデザイン上の問題もあって考えにくく、そもそもウィジェットの生成数は制限値で決められているようにそれほど多くはありません。
したがって現実的にはウィジェットの描画ではなく、
多量の図形の描画で起きる可能性のほうが高いです。図形の描画数の上限は極端に大きいため、その気になればキャンバスを多くの図形で埋め尽くすことができるからです。
そのほかに頻度は低いですが、
テキストウィジェットに非常に多数の文字列を表示することでも起きることがあります。
コマンド・キューの満杯は以下のようなことが組み合わさって起きます。
- 図形の数:
- 描画する図形数が多い(数百、数千以上)
- 時間:
- 一気に数多くの図形を描画する
- CPU能力:
- GUIエンジンの性能はCPUに依存する。能力の低いCPUは起きる可能性が高くなる
アプリケーションの種類でよくあるものとして、たとえばフラクタル図形の描画や、自立走行するゲームなど、開始ボタンを押したあとは人が介在せずに延々と走りつづけるタイプ(=描画の様子を鑑賞することが目的のプログラム)で見られます。
■症状
数多くの図形を描画している最中にパタっと描画が止まり、少し間をおいて再び描画が始まるが描画が遅い・・という現象が見られます。しかし動作異常というわけでもなく、プログラムが落ちたりすることはありません。
この「パタッと描画が止まる」のがコマンド・キューが満杯になった時の症状です。
この現象はGUIエンジン(Tcl/Tk)の特性によるものであり障害ではないことをご理解願います。次に示す対策により回避可能です。
■回避方法
GUIエンジンが高負荷になる現象は、Mind側の実行とGUIエンジン側のそれとでCPUの時間配分が不公平であることに起因しています。これを解消する最も効果的な対応は、
「25 イベント処理」-「長くかかる処理の配慮」 で取り上げた「○○の保留イベントを処理」を使う方法になります。
25章での解説では、Mindの処理が長くかかるとマウスやキーボードが反応しなくなるという現象への対処として書かれていますが、実は同じ手法をGUIエンジンの高負荷を避ける目的でも使えます。(GUIエンジンになるべくCPU時間を与えるという趣旨では同じです)
具体的には、図形描画だけを延々と続けるのではなく、ある数だけ繰り返したらGUIエンジンに少し時間を与える・・という方法をとります。
たとえば次のようなプログラムが考えられます。
プログラム例:
描画数は 変数。
描画処理とは
描画数を クリアし
ここから
・・・図形描画の処理・・
描画数を 一つ増加し
描画数が 100 以上
ならば 描画数を クリアし
少しの保留イベントを処理し
つぎに
繰り返すこと。
上のプログラムによれば、100個の図形を描画するごとに1回 「
少しの保留イベントを処理」 を呼ぶことになり、たくさんの図形描画中であっても時々、GUIエンジンに制御を渡すことができます。
(100はあくまで例なので、アプリケーションによって最適な数を決めてください)
25章によれば類似した単語として以下の3つを挙げています。
一つの保留イベントを処理
少しの保留イベントを処理
すべての保留イベントを処理
上記の「一つの・・」はGUIエンジンへ制御を渡す時間がやや短かく、「すべての・・」は本目的としては逆に長すぎることから、その中間である「少しの保留イベントを処理」が適当となります。
このほかの対応策としては、「n秒待ち」系の時間待ち単語、あるいは「遅延」を使うことで、描画処理の合間に適度なディレイを入れる方法もあります。先の「少しの保留イベントを処理」に比べると明にアイドル時間を作り出すため効果は高いですが、そのぶんアプリケーションの走行が遅くなるのでケース・バイ・ケースで使い分けてください。(図形描画を観賞することが目的のプログラムなど、ゆっくりした走行が似合う場合はこちらが向いているでしょう)
■ユーザが作成したプログラムを配布する場合
ソフト開発者が使うPCは一般的に高性能であることが多い一方で、作成したプログラムを配布するようなケースでは、それを受け取ったユーザのPCの性能が低いこともあり得ます。
したがって、Mind9でGUIアプリケーションを作る際、開発段階ではGUIエンジンの高負荷問題を感じない場合であっても、そのアプリケーションを他者に使ってもらうような場合には予防的に前記した対処をおこなっておくことを勧めます。
具体的には、前記した「少しの保留イベントを処理」を挿入するとか、あるいは、図形の描画数をあまり過大にしない、処理を開始したあと無限に描画を続けるのではなく一定時間経過で停止する・・などの方策が予防になります。