2009-04-21 5 views
59

私は最近、DataAccessProviderとビジネスロジックレイヤーを区別するためのインターフェースレイヤーを作成しました。 このアプローチでは、Web/App.Configの値を変更して、いつでもDataAccessProviderの選択を変更できます。 (必要に応じて詳細を記入してください)。リフレクションの遅さ

これを行うには、私たちが作業できるDataProviderクラスを実現するためにリフレクションを使用します。

/// <summary> 
/// The constructor will create a new provider with the use of reflection. 
/// If the assembly could not be loaded an AssemblyNotFoundException will be thrown. 
/// </summary> 
public DataAccessProviderFactory() 
{ 
    string providerName = ConfigurationManager.AppSettings["DataProvider"]; 
    string providerFactoryName = ConfigurationManager.AppSettings["DataProviderFactory"]; 
    try 
    { 
     activeProvider = Assembly.Load(providerName); 
     activeDataProviderFactory = (IDataProviderFactory)activeProvider.CreateInstance(providerFactoryName); 
    } 
    catch 
    { 
     throw new AssemblyNotFoundException(); 
    } 
} 

しかし、今私はどのように遅い反射があるのだろうか?

+4

これをベンチマークするテストハーネスを作成するのは簡単でしょうか? – marijne

+2

工場がシングルトンの場合、Assembly.Loadは一度だけ呼び出されますか? – CVertex

+0

http://stackoverflow.com/questions/25458/how-costly-is-net-reflection?rq=1 – nawfal

答えて

72

ほとんどの場合、十分に速いです。たとえば、これを使用してDALラッパーオブジェクトを作成する場合、リフレクションによってオブジェクトを作成するのにかかる時間は、ネットワークに接続する必要がある時間に比べて小文字のになります。これを最適化することは時間の無駄になります。あなたがタイトループ内で反射を利用している場合は

は、それを改善するためのトリックがあります。

  • ジェネリック型指定されたデリゲートに
  • Delegate.CreateDelegate((ラッパーwhere T : new()MakeGenericTypeを使用して);動作しません。コンストラクタ用)
  • Reflection.Emit - ハードコア
  • Expression(のようなDelegate.CreateDelegateが、より柔軟性、およびコンストラクタのために働く)

しかし、あなたの目的では、CreateInstanceは完全に問題ありません。それにこだわり、物事を単純にしておきなさい。


編集:最も重要なことは、「それを測定」は残っており、一方、相対的なパフォーマンスについてのポイントが残っている間、私は上記のいくつかを明確にすべきです。時々...それはです問題です。最初に測定します。しかし、と遅すぎる場合は、FastMemberのようなコードをバックグラウンドで静かに表示することをお勧めします。

var accessor = TypeAccessor.Create(type); 
List<object> results = new List<object>(); 
foreach(var row in rows) { 
    object obj = accessor.CreateNew(); 
    foreach(var col in cols) { 
     accessor[obj, col.Name] = col.Value; 
    } 
    results.Add(obj); 
} 

これは単純ですが、非常に高速です。

int id = 12345; 
var orders = connection.Query<Order>(
    "select top 10 * from Orders where CustomerId = @id order by Id desc", 
    new { id }).ToList(); 
:具体的な例では、私は再びあなたに最速が、使いやすいAPIを提供するために、バックグラウンドですべて Reflection.Emitのコードを実行し dapperのようなDALあなたはこのたくさんやっている場合は、ラッパー、考える何か、について言及しますここ
+2

フィールドにアクセスするために反射発光がどのように機能するかを誰かが見たいと思っている人は、それほど複雑ではありません。http: //sharpanalytics.blogspot.de/2012/08/dynamic-methods-for-accessing-fields.html – SACO

+0

@Marc:\t 私はメソッドを取得するためにリフレクションを使用していますが、現在のメソッドのクラス名をtryにエラーを記録する-キャッチ。基本的には、エラーログ中に関数名のハードコーディングを避けるためです。私は心配する必要がありますか? –

+1

@Sangramおそらく、ない –

9
+5

ショックを受けないでください。測定された最長時間は100万回の反復で22秒でした。最悪の場合、通話あたり22 *マイクロ*秒。膨大な数のオブジェクトを作成していない限り、大きな問題ではありません。もちろん、あなたが*これらのオブジェクトの膨大な数を作成しているなら、それは大きな問題かもしれませんが、Marcが指摘しているように、それはまだデータベースの接続とクエリ時間に悩まされます。パフォーマンスが重要であることが分かっている場合を除き、「x回遅い」記事で気にしないでください。 – itowlson

+0

私はそれが遅いですが、ほとんどのアプリケーションでは、パフォーマンスのペナルティは反射を使用する利点を上回ることはありません。 –

3

他の回答に記載されているリンクをたどり、あなたが "病的に悪い"コードを書いていないことを保証する以外に、私にとってこれに対する最良の答えはあなた自身でテストすることです。

ボトルネックの位置、リフレクションコードのユーザー数、リフレクションコードのタイトループの有無などは知っているだけです。あなたのビジネスケース、サイトにアクセスするユーザーの数、 perf要件があります。

しかし、ここに示したコードのスニペットを考えれば、反射のオーバーヘッドは大きな問題にはならないと私は推測します。

VS.NETのWebテストとパフォーマンステストの機能は、このコードのパフォーマンスをかなり簡単に測定する必要があります。

リフレクションを使用しない場合、コードはどのように見えますか?それにはどんな制限がありますか?リフレクションコードを削除した場合、自分が見つけた限界を乗り越えることができない可能性があります。可能であるかどうか、あるいは代替が望ましいかどうかを確認するためにリフレクションなしでこのコードを設計しようとする価値があるかもしれません。

5

反射が遅いわけではありません。反射によるメソッドの呼び出しは、通常の方法よりも約3倍遅くなります。これを1回だけ、または重要ではない状況で行うと、問題はありません。タイムクリティカルな方法で10,000回使用する場合は、実装を変更することを検討します。

+0

これが当てはまる場合、私はこのステートメントが本当に好きです。 「反射による方法の呼び出しは、通常の方法よりも約3倍遅い」あなたは参考文献を持っていますか? –

+0

私の投稿は約3歳ですが、私はこの情報をどこから入手したのか思い出せません。 – Enyra

+0

FieldInfoとPropertyInfo GetValue SetValueからデータアクセス層をコンパイル済みの式に変換しました。 40列の30,000行を読み込むのにかかる時間は、4秒から1秒に短縮されました。しかし、並列比較では、値を設定して取得するときに、リフレクションはコンパイルされた式よりも200〜250倍遅くなります。 – Loathing

16

無反射コードと比較して遅いです。重要なことは、その遅い場合ではないが、その遅い場合ここでそれはを数えます。例えば、予想される集約が最大10Kまで上がるWeb環境でリフレクションを使用してオブジェクトをインスタンス化すると、オブジェクトは遅くなります。

とにかく、その性能はあらかじめ心配する必要はありません。物事が遅いと判明した場合、将来的に最適化が必要と思われる部分がローカライズされるように物事を正しく設計すれば、それらをスピードアップすることができます。

あなたがスピードアップする必要がある場合は、この有名な記事をチェックすることができます。

Dynamic... But Fast: The Tale of Three Monkeys, A Wolf and the DynamicMethod and ILGenerator Classes

+1

URLはこれで変更されたようですが、現在は http://www.codeproject.com/Articles/19513/Dynamic-But-Fast-The-Tale-of-Three-Monkeys-A- Wolf – GrandMasterFlush

0

私はのIoCと一緒に遊ん始めるまで、私はsomethign同様のをやっていました。私はSpringオブジェクト定義を使用して、SQL、XML、またはMockのデータプロバイダを指定します。

+0

Spring.netは実行時に依存関係をかなり更新することができます。設定ファイルを更新し、ファクトリからインスタンスをリロードすると、更新されたインスタンスへの参照が取得されます。 (別のspring XMLファイルを使用する場合に限り、app.configからconfigをロードすると、これは機能しません。 – Jacob

2

私は、どのように遅い反射が比較されないかを実証するための簡単なテストを行うと思いました。リフレクション

  • 合計時間をその属性のそれぞれを反復処理と照合することによって58個のオブジェクトをインスタンス化して

    52254ナノ秒

    while (reader.Read()) { 
        string[] columns = reader.CurrentRecord; 
        CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry(); 
        IEnumerable<PropertyInfo> rawPayFileAttributes = typeof(CdsRawPayfileEntry).GetProperties().Where(prop => Attribute.IsDefined(prop, typeof(CustomIndexAttribute))); 
        foreach (var property in rawPayFileAttributes) { 
         int propertyIndex = ((CustomIndexAttribute)property.GetCustomAttribute(typeof(CustomIndexAttribute))).Index; 
         if (propertyIndex < columns.Length) 
          property.SetValue(toReturn, columns[propertyIndex]); 
         else 
          break; 
        } 
    } 
    

反射も取得することがあるので868ナノ秒

while (reader2.Read()) { 
     string[] columns = reader2.CurrentRecord; 
     CdsRawPayfileEntry toAdd = new CdsRawPayfileEntry() { 
      ColumnZero = columns[0], 
      ColumnOne = columns[1], 
      ColumnTwo = columns[2], 
      ColumnThree = columns[3], 
      ColumnFour = columns[4], 
      ColumnFive = columns[5], 
      ColumnSix = columns[6], 
      ColumnSeven = columns[7], 
      ColumnEight = columns[8], 
      ColumnNine = columns[9], 
      ColumnTen = columns[10], 
      ColumnEleven = columns[11], 
      ColumnTwelve = columns[12], 
      ColumnThirteen = columns[13], 
      ColumnFourteen = columns[14], 
      ColumnFifteen = columns[15], 
      ColumnSixteen = columns[16], 
      ColumnSeventeen = columns[17] 
     }; 
    } 

完全に公平ではない、とはいえ:

  • 合計時間を新しいオブジェクトを作成することによって、58個のオブジェクトのインスタンス化反射せずに

    • リフレクションによって新しいオブジェクトを作成する上で、すべてのプロパティの特定の属性が58 * 18回ありますが、少なくともいくつかの観点があります。

  • 関連する問題