2009-04-21 83 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 2009-04-21 08:05:36

+2

如果工廠是單身人士,那麼Assembly.Load只會被調用一次? – CVertex 2009-04-21 08:07:40

+0

http://stackoverflow.com/questions/25458/how-costly-is-net-reflection?rq=1 – nawfal 2013-06-08 23:50:30

回答

72

在大多數情況下:速度不夠快。例如,如果您正在使用它來創建DAL包裝器對象,則與連接網絡所需的時間相比,通過反射創建該對象所需的時間爲極小的。所以優化這將是浪費時間。

如果您在緊張的循環使用反射,有技巧,以提高它:

  • 泛型(使用包裝where T : new()MakeGenericType
  • Delegate.CreateDelegate(一個類型代表;不工作對構造)
  • Reflection.Emit - 鐵桿
  • Expression(如Delegate.CreateDelegate,但更靈活,適用於構造函數)

但爲了您的目的,CreateInstance是完全沒問題的。堅持這一點,並保持簡單。


編輯:儘管關於相對錶現的觀點依然存在,而最重要的事情「衡量它」仍然存在,但我應該澄清一些上述內容。有時......它確實的問題。先測量一下。然而,如果你發現它太慢了,你可能想看看FastMember這樣的代碼,它可以在後檯安靜地編碼所有Reflection.Emit代碼,給你一個很好的簡單API;例如:

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); 
} 

這很簡單,但會非常快。在具體的例子中,我提過一個DAL包裝,如果你正在做這個地段,可以考慮像dapper,這又確實在後臺的所有Reflection.Emit代碼給你以最快的速度,但易於使用的API:

int id = 12345; 
var orders = connection.Query<Order>(
    "select top 10 * from Orders where CustomerId = @id order by Id desc", 
    new { id }).ToList(); 
+2

如果有人想看看反射如何發射工作訪問字段(這不是太複雜)請參閱:http: //sharpanalytics.blogspot.de/2012/08/dynamic-methods-for-accessing-fields.html – SACO 2012-09-11 12:34:00

+0

@Marc:\t 我一直在使用反射來獲取方法,當前方法的類名記錄錯誤的嘗試-抓住。基本上是爲了避免在記錄錯誤時硬編碼函數名稱。我需要擔心嗎? – 2015-12-18 06:33:01

+1

@桑格拉姆可能不會,不, – 2015-12-18 07:38:18

3

除了遵循其他答案中給出的鏈接,並確保你沒有寫「pathalogically bad」代碼,那麼對我而言,最好的答案就是自己測試它。

只有你知道你的瓶頸在哪裏,你的反射代碼將會是多少次用戶,反射代碼是否在緊密的循環等等。你知道你的商業案例,有多少用戶將訪問你的網站,什麼perf的要求是。

但是,鑑於你在這裏顯示的代碼片段,我的猜測是反射的開銷不會是一個大問題。

VS.NET web測試和性能測試功能應該使測量這個代碼的性能非常簡單。

如果您不使用反射,您的代碼將是什麼樣子?它有什麼限制?如果你刪除了反射代碼,你可能無法忍受你發現自己的侷限性。可能值得嘗試設計此代碼而不進行反思,看看是否有可能或替代方案是否可取。

5

反射不是很慢。通過反射調用方法比普通方式慢大約3倍。如果您只做一次或在非危急情況下這樣做沒有問題。如果在時間關鍵型方法中使用它10'000次,我會考慮更改實現。

16

它比非反射代碼慢。重要的是,如果它很慢,但如果它的緩慢它在那裏計數。例如,如果您在Web環境中使用反射來實例化對象,而預期的協調性可能會上升到10K,則它會很慢。

無論如何,它的好處並不在於提前關注性能。如果事情變得緩慢,如果你正確地設計了一些事情,那麼你總是可以加速它們,這樣你預期的部分可能在未來需要優化。

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

0

我是做somethign相似,直到我開始與國際奧委會玩:

,如果你需要加快你可以檢查這個著名的文章。我將使用Spring對象定義來指定數據提供者 - SQL,XML或Mocks!

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; 
        } 
    } 
    

沒有反射

  • 通過創建一個新的對象
  • 總時間實例化58個對象: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 * 18倍,但它至少提供了一些視角。