2009-04-21 71 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倍,但它至少提供了一些视角。