通过缓存或委托调用来提高性能? [英] Improving performance by caching or delegate call?

查看:55
本文介绍了通过缓存或委托调用来提高性能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试提高下面代码的性能,我知道如何但不确定哪种方法是最好的.第一次命中需要更长的时间,但随后的命中应该更快.现在,我可以缓存 T(其中 T 是一个类),然后检查缓存以查看T"是否存在,如果存在 - 继续获取其相关信息(NamedArguments)并遍历每个 NamedArguments,最后如果条件匹配,继续设置当前属性的值.

I am trying to improve performance in the code below and kinda know how but not sure which is the best approach. The first hit will take longer but subsequent hits should be quicker. Now, I could cache T (where T is a class) and then check the cache to see if "T" exists, if so - go ahead and get its related information (NamedArguments) and go through each of the NamedArguments and finally if the criteria matches, go ahead and set the value of the current property.

我只是想让它更有效率和性能.有什么想法吗?

I just want to make it more efficient and performant. Any ideas?

var myProps = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static).Where(prop => Attribute.IsDefined(prop, typeof(MyCustomAttribute)) && prop.CanWrite && prop.GetSetMethod() != null);

foreach (var currentProperty in myProps)
{
    foreach (var currentAttributeForProperty in currentProperty.GetCustomAttributesData())
    {
        foreach (var currentNamedArgument in currentAttributeForProperty.NamedArguments)
        {
            if (string.Equals(currentNamedArgument.MemberInfo.Name, "PropName", StringComparison.OrdinalIgnoreCase))
            {
                currentAttribParamValue = currentNamedArgument.TypedValue.Value == null ? null : currentNamedArgument.TypedValue.Value.ToString();

                // read the reader for the currentAttribute value
                if (reader.DoesFieldExist(currentAttribParamValue))
                {
                    var dbRecordValue = reader[currentAttribParamValue] == DBNull.Value ? null : reader[currentAttribParamValue];

                    // set it in the property
                    currentProperty.SetValue(val, dbRecordValue, null);
                }
                break;
            }
        }
    }
}

推荐答案

DynamicMethods 或 ExpressionTrees 将比反射快得多*.您可以为某个类型构建所有属性 getter/setter 的缓存,然后将该信息缓存在 Dictionary(或 ConcurrentDictionary)中,并将类型作为键.

DynamicMethods or ExpressionTrees will be much* faster than reflection. You could build a cache of all property getter/setters for a type, and then cache that information in a Dictionary (or ConcurrentDictionary) with type as the key.

  • 发现类型信息(例如在应用启动时).
  • 为每个属性编译动态方法(一次执行所有属性).
  • 将这些方法存储在元数据类中(示例如下).
  • 将元数据缓存在某处(即使是静态字段也可以,只要访问是同步的).使用类型作为键.
  • 在需要时获取类型的元数据.
  • 找到合适的 getter/setter.
  • 调用,传递您希望对其执行操作的实例.

// Metadata for a type
public sealed class TypeMetadata<T> {

    // The compiled getters for the type; the property name is the key
    public Dictionary<string, Func<T, object>> Getters {
        get;
        set;
    }

    // The compiled setters for the type; the property name is the key
    public Dictionary<string, Action<T, object>> Setters {
        get;
        set;
    }
}

// rough invocation flow
var type = typeof( T);
var metadata = _cache[type];

var propertyName = "MyProperty";
var setter = metadata[propertyName];

var instance = new T();
var value = 12345;
setter( instance, value );

示例设置器

摘自动态方法实现(关于这个主题的好文章).

Example Setter

Excerpted from Dynamic Method Implementation (good article on the subject).

我不能保证这个确切代码有效,但我自己编写了非常相似的代码.如果您对 IL 不满意,请务必考虑使用表达式树.

I can't vouch that this exact code works, but I've written very similar code myself. If you aren't comfortable with IL, definitely consider an expression tree instead.

public static LateBoundPropertySet CreateSet(PropertyInfo property)
{
    var method = new DynamicMethod("Set" + property.Name, null, new[] { typeof(object), typeof(object) }, true);
    var gen = method.GetILGenerator();

    var sourceType = property.DeclaringType;
    var setter = property.GetSetMethod(true);

    gen.Emit(OpCodes.Ldarg_0); // Load input to stack
    gen.Emit(OpCodes.Castclass, sourceType); // Cast to source type
    gen.Emit(OpCodes.Ldarg_1); // Load value to stack
    gen.Emit(OpCodes.Unbox_Any, property.PropertyType); // Unbox the value to its proper value type
    gen.Emit(OpCodes.Callvirt, setter); // Call the setter method
    gen.Emit(OpCodes.Ret);

    var result = (LateBoundPropertySet)method.CreateDelegate(typeof(LateBoundPropertySet));

    return result;
}

*根据我的经验快 25-100 倍

这篇关于通过缓存或委托调用来提高性能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆