反射测试未显示预期数字
我编写了一些测试代码,用于比较使用直接属性访问或反射或使用委托反射的性能。但我得到的结果令人困惑,因为它表明反射并不比直接属性访问慢很多(~4%),但我认为这不是真的。有人可以告诉我我在这里做错了什么吗?
对于 5000 个项目,我得到以下结果
- 直接访问:32.2609 秒
- 反射:33.623 秒
- 使用委托反射:31.7981 秒
代码:
private static Random random = new Random((int)DateTime.Now.Ticks);
Private Dictionary<string, Delegate> delegateList = new Dictionary<string, Delegate>();
private List<ReflectClass1> dataList = new List<ReflectClass1>();
private void TestMethod2<T>()
{
foreach (var propertyInfo in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (propertyInfo.PropertyType.BaseType != typeof(ValueType))
{
Func<T, object> getPropDelegate =
(Func<T, object>) Delegate.CreateDelegate(typeof (Func<T, object>), null, propertyInfo.GetGetMethod());
delegateList.Add(propertyInfo.Name, getPropDelegate);
}
//else
//{
// Type propertyType = propertyInfo.PropertyType.GetType();
// delegateList.Add(propertyInfo.Name,
// Delegate.CreateDelegate(typeof(Func<T, TResult>), null, propertyInfo.GetGetMethod()));
//}
}
}
//http:_//stackoverflow.com/questions/1122483/c-random-string-generator
private string RandomString(int size)
{
StringBuilder builder = new StringBuilder();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
return builder.ToString();
}
private void SetUpReflectObjList()
{
for (int i = 0; i < 5000 ; i++)
{
ReflectClass1 reflectClass1 = new ReflectClass1();
reflectClass1.Prop1 = RandomString(15);
reflectClass1.Prop2 = RandomString(10);
reflectClass1.Prop3 = RandomString(10);
reflectClass1.Prop4 = RandomString(10);
reflectClass1.Prop5 = RandomString(10);
reflectClass1.Prop6 = RandomString(10);
reflectClass1.Prop7 = RandomString(10);
reflectClass1.Prop8 = RandomString(10);
reflectClass1.Prop9 = RandomString(10);
reflectClass1.Prop10 = RandomString(10);
dataList.Add(reflectClass1);
}
}
private void UseDelegateList()
{
Debug.WriteLine(string.Format(" Begin delegate performance test. item count = {0} start time: {1}",dataList.Count, DateTime.Now.ToLongTimeString()));
for (int i = 0; i < dataList.Count; i++)
{
foreach (PropertyInfo propertyInfo in typeof(ReflectClass1).GetProperties())
{
if (delegateList.ContainsKey(propertyInfo.Name))
{
Func<ReflectClass1, object> getPropDelegate = (Func<ReflectClass1, object>) delegateList[propertyInfo.Name];
Debug.Write(string.Format(" By delegates Object: {0} Property: {1} Value: {2}", i, propertyInfo.Name, getPropDelegate(dataList[i])));
}
}
}
Debug.WriteLine("");
Debug.WriteLine(string.Format(" End delegate performance test. item count = {0} end time: {1}", dataList.Count, DateTime.Now.ToLongTimeString()));
}
private void UseDirectReflection()
{
Debug.WriteLine(string.Format(" Begin direct reflection performance test. item count = {0} start time: {1}", dataList.Count, DateTime.Now.ToLongTimeString()));
for (int i = 0; i < dataList.Count; i++)
{
foreach (PropertyInfo propertyInfo in typeof(ReflectClass1).GetProperties())
{
if (propertyInfo == null) continue;
{
Debug.Write(string.Format(" By reflection Object: {0} Property: {1} Value: {2}", i, propertyInfo.Name, propertyInfo.GetValue(dataList[i], null)));
}
}
}
Debug.WriteLine("");
Debug.WriteLine(string.Format(" End direct reflection performance test. item count = {0} end time: {1}", dataList.Count, DateTime.Now.ToLongTimeString()));
}
private void DirectOutputTest()
{
Debug.WriteLine(string.Format(" Begin direct output benchmark. item count = {0} start time: {1}", dataList.Count, DateTime.Now.ToLongTimeString()));
for (int i = 0; i < dataList.Count; i++)
{
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop1", dataList[i].Prop1));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop2", dataList[i].Prop2));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop3", dataList[i].Prop3));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop4", dataList[i].Prop4));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop5", dataList[i].Prop5));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop6", dataList[i].Prop6));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop7", dataList[i].Prop7));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop8", dataList[i].Prop8));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop9", dataList[i].Prop9));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop10", dataList[i].Prop10));
}
Debug.WriteLine("");
Debug.WriteLine(string.Format(" End direct output benchmark. item count = {0} end time: {1}", dataList.Count, DateTime.Now.ToLongTimeString()));
}
I have written some test code for comparing the performance of using direct property access or reflection or reflection by using delegates. But the results that I get are baffling, since it is showing that reflection is not much slower (~4%) than direct property access, which I do not believe to be true. Could someone tell me if I am doing something wrong here?
for 5000 items I am getting the below results
- direct access: 32.2609 secs
- reflection: 33.623 secs reflection by
- using delegates: 31.7981 secs
Code:
private static Random random = new Random((int)DateTime.Now.Ticks);
Private Dictionary<string, Delegate> delegateList = new Dictionary<string, Delegate>();
private List<ReflectClass1> dataList = new List<ReflectClass1>();
private void TestMethod2<T>()
{
foreach (var propertyInfo in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (propertyInfo.PropertyType.BaseType != typeof(ValueType))
{
Func<T, object> getPropDelegate =
(Func<T, object>) Delegate.CreateDelegate(typeof (Func<T, object>), null, propertyInfo.GetGetMethod());
delegateList.Add(propertyInfo.Name, getPropDelegate);
}
//else
//{
// Type propertyType = propertyInfo.PropertyType.GetType();
// delegateList.Add(propertyInfo.Name,
// Delegate.CreateDelegate(typeof(Func<T, TResult>), null, propertyInfo.GetGetMethod()));
//}
}
}
//http:_//stackoverflow.com/questions/1122483/c-random-string-generator
private string RandomString(int size)
{
StringBuilder builder = new StringBuilder();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
return builder.ToString();
}
private void SetUpReflectObjList()
{
for (int i = 0; i < 5000 ; i++)
{
ReflectClass1 reflectClass1 = new ReflectClass1();
reflectClass1.Prop1 = RandomString(15);
reflectClass1.Prop2 = RandomString(10);
reflectClass1.Prop3 = RandomString(10);
reflectClass1.Prop4 = RandomString(10);
reflectClass1.Prop5 = RandomString(10);
reflectClass1.Prop6 = RandomString(10);
reflectClass1.Prop7 = RandomString(10);
reflectClass1.Prop8 = RandomString(10);
reflectClass1.Prop9 = RandomString(10);
reflectClass1.Prop10 = RandomString(10);
dataList.Add(reflectClass1);
}
}
private void UseDelegateList()
{
Debug.WriteLine(string.Format(" Begin delegate performance test. item count = {0} start time: {1}",dataList.Count, DateTime.Now.ToLongTimeString()));
for (int i = 0; i < dataList.Count; i++)
{
foreach (PropertyInfo propertyInfo in typeof(ReflectClass1).GetProperties())
{
if (delegateList.ContainsKey(propertyInfo.Name))
{
Func<ReflectClass1, object> getPropDelegate = (Func<ReflectClass1, object>) delegateList[propertyInfo.Name];
Debug.Write(string.Format(" By delegates Object: {0} Property: {1} Value: {2}", i, propertyInfo.Name, getPropDelegate(dataList[i])));
}
}
}
Debug.WriteLine("");
Debug.WriteLine(string.Format(" End delegate performance test. item count = {0} end time: {1}", dataList.Count, DateTime.Now.ToLongTimeString()));
}
private void UseDirectReflection()
{
Debug.WriteLine(string.Format(" Begin direct reflection performance test. item count = {0} start time: {1}", dataList.Count, DateTime.Now.ToLongTimeString()));
for (int i = 0; i < dataList.Count; i++)
{
foreach (PropertyInfo propertyInfo in typeof(ReflectClass1).GetProperties())
{
if (propertyInfo == null) continue;
{
Debug.Write(string.Format(" By reflection Object: {0} Property: {1} Value: {2}", i, propertyInfo.Name, propertyInfo.GetValue(dataList[i], null)));
}
}
}
Debug.WriteLine("");
Debug.WriteLine(string.Format(" End direct reflection performance test. item count = {0} end time: {1}", dataList.Count, DateTime.Now.ToLongTimeString()));
}
private void DirectOutputTest()
{
Debug.WriteLine(string.Format(" Begin direct output benchmark. item count = {0} start time: {1}", dataList.Count, DateTime.Now.ToLongTimeString()));
for (int i = 0; i < dataList.Count; i++)
{
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop1", dataList[i].Prop1));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop2", dataList[i].Prop2));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop3", dataList[i].Prop3));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop4", dataList[i].Prop4));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop5", dataList[i].Prop5));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop6", dataList[i].Prop6));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop7", dataList[i].Prop7));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop8", dataList[i].Prop8));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop9", dataList[i].Prop9));
Debug.Write(string.Format(" direct output benchmark Object: {0} Property: {1} Value: {2}", i, "Prop10", dataList[i].Prop10));
}
Debug.WriteLine("");
Debug.WriteLine(string.Format(" End direct output benchmark. item count = {0} end time: {1}", dataList.Count, DateTime.Now.ToLongTimeString()));
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
有两件事:
反射的性能在较新的运行时中已经变得更好,因为它是 .NET 语言的主要功能,并且因为人们对静态和动态性能之间的差异给予了很多关注。我假设您在 Framework v3.5 或 4.0 中运行它;如果您要在 Framework v2.0 中执行此代码,它的性能可能会更差。
您所做的大部分工作都不是非常“大量”使用反射。动态属性调用有点繁重,但您所做的大部分工作只是获取信息。真正的重磅人物是动态方法调用和动态实例创建。
假设您运行了以下测试。非常简单,唯一不同的是静态实例化和调用与反射:
如果您想确保测试完全公平,您可以删除内部 for 循环并使用字符串“Method1”、“Method2”调用 GetMethod 6 次 反射测试不仅
动态调用方法,它还搜索清单以查找并实例化 Type 对象,然后从 Type 动态实例化实际对象,并在该对象上动态调用方法。我敢打赌,如果您运行这两个测试,第二个测试的表现会更差。另外,探索向这些方法传递参数;首先,您必须找到正确的重载,然后反射调用采用 Object[] 数组,该数组将装箱和取消装箱方法的任何值类型参数,从而进一步减慢反射算法的速度。
简而言之,反射会比静态算法表现更差;然而,在提高其性能方面已经取得了长足的进步,因此从 .NET 4.0 开始,智能编写的动态算法与对应的静态算法相比并没有那么大的损失,使得反射在需要时更加可行。
编辑:并行运行上述 2 个测试后,存在很大的相对差异:静态算法 100k 次迭代需要 0.07 秒,反映了高达 2.12 秒。反射实例化/调用比静态要花费 30 倍的时间。然而,需要 100,000 次迭代后差异才显着;到目前为止,我最初的测试中的 Debug.WriteLine 语句是这两个测试中最慢的部分。
2 things:
Performance of reflection has gotten much better in newer runtimes, because it is a major power of .NET languages and because so much attention has been paid to the difference between static and dynamic performance. I assume you're running this in Framework v3.5 or 4.0; If you were to execute this code in the Framework v2.0, it would probably perform more poorly.
Most of what you're doing is not very "heavy" use of reflection. Dynamic property invocation is kind of heavy, but most of what you're doing is just getting information. The real heavy-hitters are dynamic method invocation and dynamic instance creation.
Say that you ran the following test. Very simple, and the only thing different is static instantiation and invocation vs reflective:
If you wanted to make sure the testing was completely fair, you could remove the inner for loop and call GetMethod 6 times with string literals "Method1", "Method2", etc.
The reflection test not only invokes methods dynamically, it searches the manifest to find and instantiate a Type object, then it dynamically instantiates the actual object from the Type, on which the methods are dynamically called. I would bet that if you ran both tests, the second one would perform much more poorly. Also, explore passing parameters to these methods; First you have to find the right overload, then the reflective invocation takes an Object[] array, which will box and unbox any value-type parameters of the method(s), further slowing the reflective algorithm down.
In short, reflection will perform more poorly than a static algorithm; HOWEVER there have been great strides made to improve its performance, so as of .NET 4.0, an intelligently-written dynamic algorithm is not such a huge loss versus a counterpart static algorithm, making reflection far more viable when needed.
EDIT: After running the above 2 tests side by side, there is a big relative difference: static algorithm 0.07s for 100k iterations, reflective a whopping 2.12s. Reflective instantiation/invocation takes 30 times longer than static. However, the difference took 100,000 iterations to be significant; the Debug.WriteLine statements in my original incarnation of this test were, by far, the slowest part of either test.
我重写了您的测试,仅访问内部循环中的属性,而不使用事物列表,并得到以下结果:
调试:
发布:
当然,如果您没有访问该属性数百万次,那么性能影响对于您的应用程序来说真的很重要吗?
I rewrote your test to just access the property in the inner loop and not use a list of things and got the following results:
Debug:
Release:
Of course if you arent accessing the property millions of times then does the performance impact actually matter for your application?
这是真的。从相对论的角度来看,反思通常很慢,但从日常值得担心的角度来看,反思通常并不慢。这是一篇关于反射缓慢部分和不那么慢部分的精彩文章:反射文章
我认为担心反射属于过早优化的范畴。如果表达设计的最佳方式是使用反射,那么就使用它。否则不要。另外,我会小心地在只执行该代码的循环中运行代码并尝试收集一些有意义的数字。您最终会对一些对您的应用程序实际上没有影响的东西进行微观优化。
Its true. Reflection is usually slow in relativistic terms, but not usually slow in day-to-day worth worrying about terms. Here's a great article on the slow parts of reflection and the not-so-slow parts: Reflection Article
I think worrying about reflection falls into the premature optimization category. If the best way to express your design is to use reflection then use it. Otherwise don't. Also, I'd be careful about running code in an loop that executes just that code and attempting to glean some meaningful numbers. You'll end up micro-optimizing something that really had no impact in your application.