DIコンテナにおける自動処理の有無と初期化時間の比較 (その2)

前回のエントリに対して、ひがさんからコメントを頂いた。

プロパティのリフレクション情報をキャッシュしてます?
キャッシュしてれば、それほど変わらない気がするんですけど

.NETは、JavaのようにBeanDescのようなクラスを経由せず、型(Type)クラスから直接リフレクションによるプロパティ情報を取得できるため、例えば、ある型のプロパティ情報から、自動バインディングの対象となるものを全て取得するには、このように書ける。

PropertyInfo[] props = Array.FindAll(type.GetProperties(
     BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance |  BindingFlags.FlattenHierarchy), 
    delegate(PropertyInfo info)
    {
        return (infoが参照するプロパティは、まだバインディングの対象になっていない);※
    });
※(infoが参照するプロパティは、まだバインディングの対象になっていない)、というブール値の式を正確に書こうとすると、そのコンテキストからしてかなり長いコード片を書かなくてはならないので、コード片は割愛した。

このようなGenericsメソッドを用い、対象のプロパティ情報を配列に格納して自動バインディングに使用しているだけである。特にキャッシュなどをしている訳ではないが、バインディング対象のプロパティにもう一段階の絞込みを行ってやることで、少しでも処理速度が改善できないか試してみた。具体的には、プロパティが自動バインディングの対象となるには、そのプロパティの型がインタフェースであるかどうかの検査が後々必ず入るので、上記のPredicateデリゲートを以下のようにしてみただけである。

    delegate(PropertyInfo info)
    {
        return (infoが参照するプロパティは、まだバインディングの対象になっていない) && (info.PropertyType.IsInterface);
    }

これにより、サンプルでDIの対象としてきたSystem.Windows.Forms.Formクラスの派生クラスにおいて、自動バイディングの候補となるプロパティの数を126個から5個に減らすことができた。
この状態で、前回と同様にDIコンテナの初期化にかかった時間を計測してみたところ、

                        1回目   2回目
                                                                        • -
上記の改造前 : 2109ms, 2140ms 上記の改造後 : 1328ms, 1344ms
                                                                          • -
自動バインディング無: 1234ms, 1250ms 自動登録、初期化も無: 906ms, 922ms

と、700ms程度の改善が見られた。それでも自動バインディング無しに比べて100ms、最も処理を省略した状態と比べて、400ms程度の差があるが、これなら気にならない程度だろうか。(何度も書いているが、サーバアプリケーションでは全く気にする必要の無い時間差だろう。)

しかし、このようにプロファイル->リファクタリングを繰り返して性能に不満がある部分を詰めていく作業ってのは、プレッシャーが掛からない状況であれば実に楽しい。xUnitテストと同様に結果が見える、実感できるってのが重要なんだろう。