gpt4 book ai didi

c# - 反射测试未显示预期数字

转载 作者:太空狗 更新时间:2023-10-29 22:28:33 26 4
gpt4 key购买 nike

我已经编写了一些测试代码来比较使用直接属性访问或反射或使用委托(delegate)进行反射的性能。但我得到的结果令人费解,因为它表明反射并不比直接访问属性慢很多(~4%),我不认为这是真的。如果我在这里做错了什么,有人可以告诉我吗?


对于 5000 个项目,我得到以下结果

  • 直接访问:32.2609 秒
  • 反射(reflection):33.623 秒反射(reflection)
  • 使用委托(delegate):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()));
}

最佳答案

2 件事:

  • 反射的性能在较新的运行时中变得更好,因为它是 .NET 语言的主要功能,并且因为人们非常关注静态和动态性能之间的差异。我假设您在 Framework v3.5 或 4.0 中运行它;如果您要在 Framework v2.0 中执行此代码,它的性能可能会更差。

  • 您所做的大部分工作都不是很“大量”地使用反射。动态属性调用有点繁重,但您所做的大部分工作只是获取信息。真正的重头戏是动态方法调用和动态实例创建。

假设您运行了以下测试。非常简单,唯一不同的是静态实例化和调用与反射:

public class ReflectionTest
{
public int Method1(){return 1;}
public int Method2() { return 2; }
public int Method3() { return 3; }
public int Method4() { return 4; }
public int Method5() { return 5; }
public int Method6() { return 6; }
}

[Test]
public void TestStatic()
{
for (var i = 1; i <= 100000; i++)
{
var reflectTest = new ReflectionTest();
reflectTest.Method1();
reflectTest.Method2();
reflectTest.Method3();
reflectTest.Method4();
reflectTest.Method5();
reflectTest.Method6();
}
}

[Test]
public void TestReflection()
{
var fullName = typeof (ReflectionTest).FullName;
for (var i = 1; i <= 100000; i++)
{
var type = Assembly.GetExecutingAssembly().GetType(fullName, true, true);
var reflectTest = Activator.CreateInstance(type);
for (var j = 1; j <= 6; j++)
type.GetMethod("Method" + j.ToString()).Invoke(reflectTest, null);
}
}

如果您想确保测试完全公平,您可以删除内部 for 循环并使用字符串文字“Method1”、“Method2”等调用 GetMethod 6 次。

反射测试不仅动态调用方法,它搜索 list 以找到并实例化一个 Type 对象,然后动态实例化来自 Type 的实际对象,在该对象上动态调用方法。我敢打赌,如果您同时运行这两个测试,那么第二个测试的表现会差得多。此外,探索将参数传递给这些方法;首先,您必须找到正确的重载,然后反射调用采用一个 Object[] 数组,该数组将装箱和拆箱方法的任何值类型参数,进一步减慢反射算法的速度。

简而言之,反射会比静态算法表现更差;然而,在提高其性能方面取得了长足的进步,因此从 .NET 4.0 开始,智能编写的动态算法与对应的静态算法相比并没有那么大的损失,使得反射在需要时更加可行。

编辑:并排运行上述 2 个测试后,相对差异很大:100k 次迭代的静态算法 0.07 秒,反射高达 2.12 秒。反射实例化/调用比静态实例化/调用花费的时间长 30 倍。但是,差异需要 100,000 次迭代才能显着; Debug.WriteLine 语句在我最初的测试中是迄今为止这两个测试中最慢的部分。

关于c# - 反射测试未显示预期数字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5239310/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com