Weitere ähnliche Inhalte
Ähnlich wie Msを16倍出し抜くwpf開発1回目 (6)
Kürzlich hochgeladen (11)
Msを16倍出し抜くwpf開発1回目
- 2. 誰のためか
対象者
C#と.NET Frameworkに対する大まかな知識を持つ人
WPFに対する大まかな知識を持つ人
動機
WPFのプログラムの動作が遅いという懸念や不満
- 6. 一般的手法
(今日は一部しか扱いま
せんが)
正しいデータ構造(コレクションの特性を活かす)
求められるのは変更に対する強さなのか、検索に対する高速性
なのか、列挙の速度なのか、省メモリなのか。
効率的なアルゴリズム
データ構造に合わせた手法を選ぶ。
同じ処理を無駄に繰り返さないこと(遅延評価、イベント集約
等は重要なテクニック)。
チューニング
コードのほとんどはループ。ループを速くすれば速くなる。し
ないループ(省略したループ)が最も早い。
短いコードは速いことが多い(LINQは例外)。
ボトルネックの発見と除去(ベンチマークは徹底的に)。
この色の部分はマイクロソフトが極めて重視してます。
- 7. .NET Framework
では
(この部分も今日のネタ
ではありませんが)
糖衣構文(シンタックスシュガー)の解釈に対する正しい理
解
メモリ転送量と演算量を把握すること。
ガーベージコレクションの動きを把握すること。
IL(中間コード)を確認しながらコードを書くこと。
いやそもそも、どんな機械語になるのか理解すること。
- 8. WPFでは
(構造を知ってないと、
一般的手法を役立てる場
所を見失います)
4つのパスを理解すること(時間軸の区分)
イベント処理とユーザーコード
バインディングパス
レイアウトパス
描画パス
情報の所在と関連を理解すること(メモリ空間軸の区分)
アンマネージ領域
OSに依存するリソース群
マネージ領域
クラスと構造体
ビジュアルツリーとロジカルツリー
依存関係プロパティ
描画命令バッファ(隠ぺいされている)
テクスチャ(隠ぺいされている)
デバイスのステート管理(隠ぺいされている)
今日のネタ
次回以降のネタ
- 9. WPFは遅い?
「悪いパターン」が内在しています
パネルの基底クラスに無駄なソートが含まれています。
依存関係プロパティへのアクセスはMicrosoftが主張するほど速
くありません。(特にPropertyMetadataの種類に気を付けま
しょう)
Microsoftが推奨しない使い方は設計通りの速度が出ません。
リッチゆえに遅い部分が存在します
実は、アンチエイリアスを解除するだけで5倍くらい高速にな
ります。
Freezeするだけで速くなる部分があります。
構造を理解せずに使うと遅いところがあります
プロパティ変更から再描画に至るまでにパスを理解していない
と、速くすることができません。
見えないコストを理解していないと、それ以前のすべての動作
と無関係に遅くなります。
本日の主なネタ
- 11. WPFの骨格1
(概念)
ユーザー
コード
• 入力やイベントの処理
• Model層の変更(データの更新)
• ViewModel層への変更通知(表示層への伝達経路)
データバイ
ンディング
• ViewModel層の変更をViewに伝達(表示の更新のための設定)
• レイアウトパス用のフラグ設定(要サイズ測定、要配置・再描画)
レイアウト
パス
• コントロールのサイズ測定
• コントロールの配置と描画内容の確定
描画パス
• 最適な方法で描画を実施する(DirectXを内部で使用しています)
MVVMという手法を用いても用いなくても、流れは同じです。
- 12. WPFの骨格2
(実装)
具体的にどこに記述され
るのか。
理想的にはこれを無駄な
く循環させたい。
ユーザー
コード
• あらゆるユーザーコード
• イベントハンドラ
データバイ
ンディング
• XAMLで記述する部分と依存関係プロパティ
• OnXXXXXChanged等
レイアウト
パス
• MeasureOverride
• ArrangeOverride/OnRender
描画パス
• 描画(要はここに速くたどり着きたいだけ)
- 14. 知るべき
共通ルール
(イベント集約とは)
プロパティA変更→
イベント
パスA パスB
プロパティA変更→
イベント
プロパティA
変更通知
同一パス内において、1変更に対して1イベントが発生しま
す。
各パスの間において、変更箇所の集約がなされているため、
次のパスは1回しか動かないようになっています。
パスとパスの間は後続処理で非同期です。
例えば、Width/Heightを変更した際に、
2回のPropertyChangedイベントが発生します。
変更の都度イベントが生じます。
しかし、レイアウトパスでの処理は1回に集約されます。
このイベント集約を活用することができると、
本来の速度を獲得できます。
(1回)
- 15. ユーザーコード
×
バインディング
依存関係プロパティを何回
変更してもバインディング
処理は1回です。
依存関係プロパティに書く
処理自体が重たいので要注
意(最小限の書き込み回数
を心がけてください)
Opacity(透過率)の設定
はコントロールに対して極
力行わないようにしましょ
う。
可能な限りFreezeしましょ
う。
バインディングはパスが違
うために非同期なので、要
注意です。
ユーザー
コード
• 入力やイベント
の処理
• Model層の変更
• ViewModel層への
変更通知
データバ
インディ
ング
• ViewModel層の変
更をViewに伝達
• レイアウトパス
用のフラグ設定
(要サイズ測定、
要配置・描画)
- 16. バインディング
×
レイアウトパス
バインディング中に、依存
関係プロパティは変更され
ます。
無限ループに陥らない範囲
でのプロパティ変更は自由
です(ただし、遅い)。
描画命令の蓄積
(OnRender)までがレイア
ウト処理です。
レイアウトパスの中で、依
存関係プロパティの変更を
すると、バインディングと
レイアウトパスはやり直し
です(初心者がはまる罠)。
データバ
インディ
ング
• ViewModel層の変
更をViewに伝達
• レイアウトパス
用のフラグ設定
(要サイズ測定、
要配置・描画)
レイアウ
トパス
• コントロールの
サイズ測定
• コントロールの
配置と描画内容
の確定
- 17. レイアウトパス
×
描画パス
OnRenderが呼ばれた順序で
描画されるわけではありま
せん。
通常はPanel.Zindexの順序
で描画されます。
内部的にはビジュアルツ
リーの親子リレーション
シップが構築された順序で
描画されます。
描画パスにはユーザーコー
ドの介在余地はありません
が、OnRenderの書き方と
Opacityの設定が悪いと遅
くなります。
レイア
ウトパ
ス
• コントロール
のサイズ測定
• コントロール
の配置と描画
内容の確定
描画パ
ス
• 最適な方法で
描画を実施す
る(DirectXを
内部で使用し
ています)
- 18. WPFの急所
3選
全パネル内の最凶ボトルネックはPanel.ZIndexのソート
子要素が1つでも変わるとZIndexを工夫もなくソートしていま
す。Childrenの着脱を最小限にする必要があります。
Canvas,Grid,StackPanel等、すべてのパネルはPanelを継承し、
Panelの機能をすべて使っています。
レイアウトパス(Measure/Arrange/OnRender)で依存関係プ
ロパティ変更をすること
再バインディングが実施されて、レイアウトパスが何度も走り
ます。
描画パスにおいてコントロールの透過率変更は極力回避。せ
めてブラシの色の透過率を変えましょう。
透過率を実現するために、一時テクスチャを生成して描画する
ことがあります。死ぬほど重いです。
そもそも透過率変更はDirect3D内部のFlush処理を呼ぶことが多
いので、描画の終了待ちが挟まれます。
次点:Freezeしていない描画要素
イベント乱れ打ち状態になる場合があります。
- 19. まとめと
次回予告
まとめ(まず1倍の速度を得ます)
流れを乱さなければ設計通りの速度を得ることができます。
実際に遅いと言われる例は、前述のパスの振る舞いを無視してい
るケースが圧倒的に多い。
急所に極力触れないようにすることが大切。
次回以降予告
ビジュアルツリーを理解しましょう。ビジュアルツリーを効率
的に再描画するアルゴリズムと実装方法。
Panel.ZIndexをどうやって解決するか。
MSDNにすら詳述されない(でもリファレンスコードを読めば
はっきりと読み取れる)最速のパネルの作り方とは・・・。
MVVMでも旧方式でも効いてくる方法があります。