はじめに
こんにちは、制作本部の藤川です。
みなさん、Silverlightで何か作ってみようとしたことはありませんか。
Silverlight開発の経験のあるかたなら一度は悩んだことがあるのがパフォーマンスの問題ではないでしょうか。
Silverlightは新しい技術であり、パフォーマンスについては、前例や参考文献も少ないのが現状です。
そこで今回は、Silverlight開発で得た経験や知識から、パフォーマンスを向上するためにはどうすればいいか、ヒントをご提供できればと思います。
また、このページの最後に参考リンクを貼っていますのでこちらもあわせてご参照ください。
パフォーマンスを向上させることによってどんなメリットがあるでしょうか。
- 動作環境の幅が広がり動くPCが増える。
- 軽快に動くことによってUIとユーザとのインタラクションがスムーズになり機会の喪失を減らすことができる。
- ファイル容量を削減することによってサーバにかける負荷を減らすことができる。
などなど、いろいろなメリットがあります。
簡単に言ってしまえば、ユーザと開発者、お互いが満足できる関係を築ける可能性が高まります。
逆に、パフォーマンスを考慮にいれていないアプリケーションはユーザの支持を得ることは難しいでしょう。
Silverlightが起動する仕組み
パフォーマンスを向上させるためにはまず、Silverlightの仕組みから見ていきましょう。
仕組みを知っていれば、パフォーマンスに関する問題がどこにあるのかを理解することができます。
また、パフォーマンスを向上させるために何をすればいいのか推測することもできます。
みなさん、.NET(ドットネット)という言葉をご存知でしょうか。
Windowsアプリケーションを開発するためにプラットフォームです。
そして、Silverlightは.NETファミリーの一員なのです。
.NETアプリケーションの実行エンジンはCLR(Common Language Runtime)と呼ばれる仮想マシンによって実行されます。
Silverlightアプリケーションの実行エンジンはCoreCLRと呼ばれ、クロスプラットフォーム、クロスブラウザを実現するためにCLRから抽出されたものを使用しています。
完成したSilverlightアプリはXap(ザップ)ファイルという1つのファイルにまとめられます。
このXapファイルをサーバからダウンロードすることにより実行されるわけです。
ダウンロードして実行される流れをもう少し詳しく見てみましょう。
実はXapファイルは、まだ完全には実行可能な状態ではありません。
Xapファイルの正体はZipファイルです。その中身は本体となるdllやマニフェストファイルなどが入っています。
つまり、本体となるdllなどは、中間言語(MSIL)と呼ばれる状態で、このままでは実行できないのです。
そこで、JIT(ジャストインタイム)コンパイルという方式でマシンコードにコンパイルしなくてはなりません。
マシンコードにコンパイルされたらCoreCLRの仮想マシンによって実行されます。
図で簡単に説明するとこのようになります。
ここで注目していただきたいのがダウロードしてから、マシンコードにコンパイルして実行されるまでの一連の流れです。
つまり、マシンコードにコンパイルする際にとてもCPUやメモリのコストをかけているということが言えます。
さらに実行してからも初期化シークエンスがあります。
そしてやっと起動することができるのです。
この一連の流れが示すものは、そのままSilverlightの起動時間を表しています。
パフォーマンスの向上において起動後の軽快さは重要ですが、起動時間も同じくらい重要です。
そして、起動時間を短縮するために私たちが行えることは次の3つです。
- ファイルサイズを小さくしダウンロードの時間を短くする。
- コードを最適化しJITコンパイルの時間を短くする。
- 余計な処理はなるべく行わないで初期化シークエンスの時間を短くする。
これらを行う必要があります
特にファーストビューに表示させる場合、ブラウザの画面を数秒間ブロッキングしてしまう可能性があるので起動時間には注意が必要です。
一度JITコンパイルされたデータはキャッシュされるため、2回目以降の起動時間は早くなります。
Silverlight4では起動時間が30%向上されたようですが、残念ながらFlashの起動時間には追いついてはいません。
今後のMicrosoft側の対応にも期待したいところです。
それでは次に具体的なパフォーマンス向上のヒントをご説明していきます。
10のヒント
ここではパフォーマンス向上に関する事柄を10個に分けてご説明します。
【1】起動は最小化
起動時に実行されるコードをできるだけ小さくすることです。
そうすることにより初期化する時間が短くなり起動時間が早くなります。
アプリケーションの初期化シーケンスでは、不要な処理は行わないほうがよいです。
遅延が許容される初期化は後で処理されるようにし、ライブラリについても直ちに読み込む必要があるかどうかを検討し、クラスやメソッドは大量のコードを読み込まないものを使用するようにします。
【2】拡張ライブラリをキャッシュさせる
アプリケーションライブラリキャッシュを使用して、拡張ライブラリをキャッシュしダウンロード時間を短くしましょう。
Silverlightには標準ライブラリ以外にも多くの拡張ライブラリが使用できます。
最初の状態では、標準ライブラリはSilverlightプラグインの中に入っているため、私たちは特に意識することなくいろいろな機能を使っています。
ただ、開発を進めていくと標準ライブラリだけでは対応できない場合があります。
例えば、Silverlightアプリケーションが外部のサーバと通信する必要があるときには、通信するための拡張ライブラリを使用しなくてはなりません。
そして、この拡張ライブラリはSilverlightプラグインには含まれていないため、Xapファイルの中にいれてダウンロードする必要があります。
ダウンロードするといってもビルドした段階で拡張ライブラリはXapファイルの中に入っていますので特に意識することはないです。
ただ、拡張ライブラリのぶんXapファイルのサイズが大きくなりダウンロードに時間がかかってしまいます。
そこでアプリケーションライブラリキャッシュを有効にすることにより、追加した拡張ライブラリがクライアントにキャッシュされ、2度目のアクセスからのダウンロード時間を短くすることができます。
また、拡張ライブラリを使用する前に一度考えるべきことがあります。
ライブラリのサイズが大きい割に使用頻度の低いものに関しては、他に変わる手段がないか検討してみてください。
例えば、1つのメソッドを使用するためだけにライブラリ全体をロードしていると、ごくわずかな機能のために多くのコストを支払うことになります。
そのメソッドの機能を、現状の機能だけでを使って再現できないかどうか検討してみるのもいいでしょう。
その他に、codeplexというオープンソース・プロジェクトがあります。
ライブラリのソースコードを公開しているので必要な機能のクラスやメソッドがあれば参照してみるといいでしょう。
【3】開発時はフレームレートを表示させる
開発時はフレームレートを表示させると細かい微調整がしやすいです。
方法は、HTMLに埋め込むときに、EnableFrameRateCounterをtrueに設定してください。
そうすると1秒あたりのフレーム数(fps)がブラウザのステータスバーに表示されます。
つまり、フレーム数が多くなっているタイミングがパフォーマンスに大きく影響を及ぼしていると推察することができます。
もし動作中に常にフレームレートが高くなっているタイミングがあるならその部分はCPUコストが多くかかってる可能性があるので調整しましょう。
ブラウザの左下にフレーム数が表示される。
【4】スペックの低いPCで動作確認
アプリケーション開発している人のPCは、重い処理にも耐えられるよう、スペックの高いPCである場合が多いです。
そこでついつい、自分が開発している環境に最適化してアプリケーションを開発してしまう場合が多くあります。
スペックの高いPCではちゃんと動いても、スペックの低いPCでは動かない、なんて事例はたくさんあるので、ちゃんと動くかどうかスペックの低いPCでも動作確認しましょう。
また、各種のブラウザ(IE、Firefox、Mac Safariなど)での動作確認も大切です。
【5】HTTPリクエストを減らす
SilverlightはブラウザのプラグインでWebサイトに埋め込まれます。
ですので、いくらSilverlight自体のパフォーマンスを向上させたところでWebサイトの全体のパフォーマンスが考慮されてないとあまり意味がありません。
Silverlightのパフォーマンス向上はWebサイトの全体のパフォーマンス向上とも密接に結びついています。
Webサイトのパフォーマンスを向上させるテクニックの一つに「HTTPリクエストを減らす」というものがあります。
これは何もWebサイトだけの話だけではなくSilverlightでも同様のことが言えます。
例えば、Xapファイルのサイズを軽くしようと考え、パーツとなる画像をサーバと通信しダウンロードしようとします。
確かに画像を内包しないXapファイルは軽くなり、単体でのダウンロード時間も早くなるでしょう。
ただ、この方法には落とし穴があります。
それはサーバにパーツとなる画像を読み込むためにHTTPリクエストを投げているという点です。
HTTPリクエストの数が多ければ多いほどWebサイト全体の読み込み速度は低下します。
もし、相手のサーバが別ドメインの外部サーバで混雑していてすぐに画像を渡してもらえなかったらどうでしょう。
その読み込み遅延はそのままSilverlightのパフォーマンスがよくないというレッテルを貼られることにつながりかねません。
頻繁に使う静的なデータはファイルサイズが大きくなろうともXapファイルの中に最初から入れておきましょう。
結果的にそのほうがSilverlightを含むWebサイト全体のパフォーマンスも向上します。
【6】なるべくXAMLで書く
UIなどの表示要素はなるべくXAML(ザムル)で書くとパフォーマンスが向上します。
XAMLとは、HTMLのようにレイアウトやデザインを指定できるXMLをベースとした、マークアップ言語の一つです。
XAMLを使用するとC#などのマネージコードをほとんど追加せずにUIを実現することが可能です。
一般的な認識として、C#などのマネージコードを使用してオブジェクトを作成したほうが軽くなると思われがちですが、大半はXAMLで書いたほうが早くなります。
それは、XAMLパーサと呼ばれる機能がXAMLファイルを解析し、オブジェクトのインスタンスを作成して初期化する過程で要素の操作に使用するAPIオブジェクトを作成せずに内部表現のみを作成するためです。
簡単に言うと、XAMLパーサをいう便利な機能があるので、素直にXAMLで書いたほうがいいということです。
【7】半透明の扱いに気をつける
半透明なUIはとても便利ですが、CPUコストがかかるため注意が必要です。
なぜなら表示されているオブジェクトに半透明を設定すると前後の要素をブレンドする必要があり、そのぶん多くのCPUコストがかかるためです。
Opacityを使用してオブジェクトを半透明にしたり、アルファチャネル付のPNG画像を使う場合など気をつけましょう。
他にもオブジェクトを非表示にすることを目的にOpacityを0%に設定し完全に透明にする方法は避けたほうがいいでしょう。
なぜなら、Opacityではオブジェクトがヒットテストされ、技術的にはレンダリングされるため、CPUコストがかかります。
単純に非表示にしたい場合はVisibilityをCollapsedに設定しましょう。
GridやCanvasなどのレイアウト要素にOpacityを設定すのも控えたほうがよいです。
グループ階層以下のオブジェクトが再計算されるためCPUコストは高くなります。
半透明は冗長的に使用するのではなく計画的、効果的に使用しましょう。
Opacityの設定は計画的に
【8】リサイズが不要な画像や動画を使う
リサイズが不要な画像や動画を使用してください。
それは拡大縮小、回転、など後で変形する必要がない画像や動画を使用してくださいということです。
画像や動画を設置するときに必要なオブジェクトの幅(Width)と高さ(Height)は明示的に設定しないほうがよいです。
なぜなら設定したスケールに再描画されるため、CPUコストがかかるからです。
特に動画は気をつけたほうがいいでしょう。
フレームごとに再描画されるため余計なCPUコストをかけている可能性があります。
画像や動画などは設計上の目的があってリサイズする必要があるならいいですが、ちょっと画像の大きさが足りなかったから拡大した、なんてのはやめたほうがよいでしょう。
【9】エフェクトの扱いに気をつける
Silverlight3からぼかし効果や、ドロップアンドシャドウ効果が使用できるようになりました。
とても便利で使い勝手のいい効果ですがパフォーマンスの観点からみれば注意が必要です。
なぜなら、これらの効果を使用するとCPUやメモリを多く使用しコストがかかります。
業務アプリケーション開発の場合ですと、ほんとにこれらの効果が必要かどうか再検討してみるのもいいでしょう。
便利だからといって使いすぎには気をつけましょう。
【10】UIに影響を与える処理は控える
Silverlightでは、UIを処理しているスレッドは1つだけなので、UI上である操作を呼び出した時に、その結果が返ってくるまで、UIをブロッキングしてしまいます。
これをWebブラウザ上で行われると、その処理中は別の操作ができなくなるので、ブラウザ全体がフリーズしたような状態になってしまいます。
実際は、処理中であったとしてもユーザはフリーズしてしまったと認識し混乱するでしょう。
UI上ではなるべく重い処理や待ち時間のかかる処理をしないようにしましょう。
BackgroundWorkerクラスなどを利用し、個別の専用スレッドをたて、重い処理を分散するなどUIスレッドに影響を与えないような設計も大切です。
【番外】GPUを活用する
ここでは少ししか触れませんがGPU機能を活用することによってパフォーマンスを向上させることができます。
ただし、GPUを活用できないPC環境のユーザには実質的にパフォーマンスが低下する可能性があると言われています。
Yahoo! JAPANでは、多くの人に利用していただくために、多種多様なPC環境に適応させる必要があるため、今のところGPU機能の利用を控えています。
しかしゲームアプリなどのターゲットとなるユーザが明確になっていれば積極的に活用したほうがよいでしょう。
さいごに
いろいろとパフォーマンス向上のヒントを上げてまいりましたがいかがでしたでしょうか。
ここで紹介した以外にもパフォーマンスを向上させるための方法はいろいろあります。
Silverlight開発の状況、ターゲットとなるユーザは千差万別です。
みなさん自身がいろいろ工夫して試みてください。
また、今年の下半期にMicrosoftからWindowsPhone7というスマートフォン向けのOSのリリースが欧米で予定されています。
WindowsPhone7はSilverlightによるアプリ開発が可能となり、Silverlightの領域はスマートフォンへと拡大していきます。
Silverlightがスマートフォンという携帯端末で動くようになるとどうなるでしょうか。
これまではPC上では問題にならなかった、バッテリーといったものが問題になってきます。
CPUコストに高い処理をずっと続けていてはバッテリーはすぐなくなってしまうことが容易に想像できます。
端末の機能をフルに活用するのはいいのですが、それですぐにバッテリーがなくなるようであれば、アプリケーションを起動することを躊躇するようになり、機会の喪失を招きかねません。
アプリ開発の舞台がスマートフォンに移ってくると、軽快に動くことはもちろんのことバッテリーを長持ちさせるためのパフォーマンスも考慮しなければならなくなります。
パフォーマンス向上というとどうしても経費削減であるとか、費用対効果、収益性の向上であるとか数値がベースの議論になりがちそこが主眼になっては意味がないと思います。
ユーザに満足のいく体験をいていただくために、パフォーマンスを向上するという目的でなければいけないと私は思います。
参考リンク
・Silverlight を使用して基幹業務エンタープライズ アプリケーションを構築する (第 1 部)
・Silverlight を使用して基幹業務エンタープライズ アプリケーションを構築する (第 2 部)
・Windows Performance Analysis Developer Center
関連記事
・認証が必要なWeb APIをSilverlightで使う方法
(R&D統括本部 藤川貴由 @udonken)
こちらの記事のご感想を聞かせください。
- 学びがある
- わかりやすい
- 新しい視点
ご感想ありがとうございました