是否可以加快这种方法的速度? [英] Is it possible to speed this method up?
问题描述
我有一个方法,它通过 7,753+
个对象使用循环并获取每个对象的每个属性的值.每个对象都有 14
个属性.
I have a method that uses loops through 7,753+
objects and Gets the value of each property for each object. Each object has 14
properties.
private void InitializeData(IList objects, PropertyInfo[] props, List<DPV> dataPs, List<Dictionary<string, object>> tod)
{
foreach (var item in objects)
{
var kvp = new Dictionary<string, object>();
foreach (var p in props)
{
var dataPs = dataPs.FirstOrDefault(x => x.Name == p.Name);
object returnData;
if (dataPoint != null)
{
int maxLength = (dataP.MaxLength == null) ? 0 : (int) dataP.MaxLength;
returnData = p.GetValue(item, null);
if (!string.IsNullOrEmpty(dataP.FormatString) && !string.IsNullOrEmpty(returnData.ToString()))
{
returnData = FormatDataForDisplay(returnData, dataP, maxLength, "", 8);
}
}
else
{
returnData = p.GetValue(item, null);
}
kvp.Add(p.Name, returnData);
}
tod.Add(kvp);
}
}
我相信 GetValue
是这个方法中花费大部分时间的方法,该方法花费了大约 900ms
来运行,但是 GetValue
被调用 800,000+
次大约需要 750 毫秒(总共,不是每次调用)
.
I believe GetValue
is what takes the majority of the time in this method, The method took around 900ms
to run, but GetValue
which is called 800,000+
times takes around 750ms (total, not per-call)
.
public List<Dictionary<string, object>> GetColumnOptions<T>(List<T> list)
{
var tod= new List<Dictionary<string, object>>();
var objects = (IList)list[0];
Type objType = objects[0].GetType();
var props = objType.GetProperties(BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance);
var dPs= GetDPs();
//Initialize aaData
//I don't believe this is correct
InitializeData2<T>(new List<T> { (T) objects}, props, dPs, tod);
return tod;
}
推荐答案
对于您的值类,您可以创建直接的 setter 和 getter lambda.
性能几乎与直接访问属性一样快.
For your value class you can create direct setter and getter lambda.
The performance is nearly as fast as directly accessing the properies.
从 PropertyInfo 获取 Setter
var propertyInfo = typeof(MyType).GetProperty("MyPropertValue");
var propertySetter = FastInvoke.BuildUntypedSetter<T>(propertyInfo));
var fieldInfo = typeof(MyType).GetField("MyFieldValue");
var fieldSetter = FastInvoke.BuildUntypedSetter<T>(fieldInfo));
循环使用
var myTarget = new MyType();
setter(myTarget, aNewValue)
检索快速 Setter 和 Getter 的助手
public static class FastInvoke {
public static Func<T, object> BuildUntypedGetter<T>(MemberInfo memberInfo)
{
var targetType = memberInfo.DeclaringType;
var exInstance = Expression.Parameter(targetType, "t");
var exMemberAccess = Expression.MakeMemberAccess(exInstance, memberInfo); // t.PropertyName
var exConvertToObject = Expression.Convert(exMemberAccess, typeof(object)); // Convert(t.PropertyName, typeof(object))
var lambda = Expression.Lambda<Func<T, object>>(exConvertToObject, exInstance);
var action = lambda.Compile();
return action;
}
public static Action<T, object> BuildUntypedSetter<T>(MemberInfo memberInfo)
{
var targetType = memberInfo.DeclaringType;
var exInstance = Expression.Parameter(targetType, "t");
var exMemberAccess = Expression.MakeMemberAccess(exInstance, memberInfo);
// t.PropertValue(Convert(p))
var exValue = Expression.Parameter(typeof(object), "p");
var exConvertedValue = Expression.Convert(exValue, GetUnderlyingType(memberInfo));
var exBody = Expression.Assign(exMemberAccess, exConvertedValue);
var lambda = Expression.Lambda<Action<T, object>>(exBody, exInstance, exValue);
var action = lambda.Compile();
return action;
}
private static Type GetUnderlyingType(this MemberInfo member)
{
switch (member.MemberType)
{
case MemberTypes.Event:
return ((EventInfo)member).EventHandlerType;
case MemberTypes.Field:
return ((FieldInfo)member).FieldType;
case MemberTypes.Method:
return ((MethodInfo)member).ReturnType;
case MemberTypes.Property:
return ((PropertyInfo)member).PropertyType;
default:
throw new ArgumentException
(
"Input MemberInfo must be if type EventInfo, FieldInfo, MethodInfo, or PropertyInfo"
);
}
}
}
============ 添加了性能分析 ====================
============= Performance Analysis Added ===================
5 个 Mio 对象,20 个属性
- 3.4s 直接访问属性
- 130.0s 通过 PropertyInfo.SetValue
- 4.0s 通过 TypedSetter(文章中显示的代码)
- 9.8s 通过 UnTypedSetter(上面的代码)
- 3.4s direct Property access
- 130.0s via PropertyInfo.SetValue
- 4.0s via TypedSetter (code shown in article)
- 9.8s via UnTypedSetter (code above)
诀窍是为每个类生成一次 property-setter 和 -getter,然后重用它们.
The trick is to generate the property-setter and -getter once for each class an reuse them.
// Create an fill objects fast from DataReader
// http://flurfunk.sdx-ag.de/2012/05/c-performance-bei-der-befullungmapping.html
static List<T> CreateObjectFromReader<T>(IDataReader reader)
where T : new()
{
// Prepare
List<string> fieldNames = GetFieldNames(reader);
List<Action<T, object>> setterList = new List<Action<T, object>>();
// Create Property-Setter and store it in an array
foreach (var field in fieldNames)
{
var propertyInfo = typeof(T).GetProperty(field);
setterList.Add(FastInvoke.BuildUntypedSetter<T>(propertyInfo));
}
Action<T, object>[] setterArray = setterList.ToArray();
// generate and fill objects
while (reader.Read())
{
T xclass = new T();
int fieldNumber = 0;
for (int i = 0; i< setterArray.Length; i++)
{
// call setter
setterArray[i](xclass, reader.GetValue(i));
fieldNumber++;
}
result.Add(xclass);
}
}
我的原始文章(德语文本和旧代码)是 https://web.archive.org/web/20141020092917/http://flurfunk.sdx-ag.de/2012/05/c-性能-bei-der-befullungmapping.html
My original article (german text and older code) was https://web.archive.org/web/20141020092917/http://flurfunk.sdx-ag.de/2012/05/c-performance-bei-der-befullungmapping.html
这篇关于是否可以加快这种方法的速度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!