Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
122 views
in Technique[技术] by (71.8m points)

c# - Is it possible to speed this method up?

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

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;
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

For your value class you can create direct setter and getter lambda.
The performance is nearly as fast as directly accessing the properies.

Get Setter from PropertyInfo

var propertyInfo = typeof(MyType).GetProperty("MyPropertValue");
var propertySetter = FastInvoke.BuildUntypedSetter<T>(propertyInfo));
var fieldInfo = typeof(MyType).GetField("MyFieldValue");
var fieldSetter = FastInvoke.BuildUntypedSetter<T>(fieldInfo));

Usage in a loop

var myTarget = new MyType();
setter(myTarget, aNewValue)

Helper to retrieving fast Setter an 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 Objects, 20 Properties

  • 3.4s direct Property access
  • 130.0s via PropertyInfo.SetValue
  • 4.0s via TypedSetter (code shown in article)
  • 9.8s via UnTypedSetter (code above)

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

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...