【问题标题】:To cache or not to cache - GetCustomAttributes缓存或不缓存 - GetCustomAttributes
【发布时间】:2009-10-23 08:38:20
【问题描述】:

我目前有一个函数:

public static Attribute GetAttribute(MemberInfo Member, Type AttributeType)
{
    Object[] Attributes = Member.GetCustomAttributes(AttributeType, true);

    if (Attributes.Length > 0)
        return (Attribute)Attributes[0];
    else
        return null;
}

我想知道是否值得将属性上的所有属性缓存到 Attribute = _cache[MemberInfo][Type]字典,

这需要使用不带任何类型参数的GetCustomAttributes,然后枚举结果。值得吗?

【问题讨论】:

    标签: c# performance reflection


    【解决方案1】:

    如果您将方法的主体替换为以下内容,您将获得更好的收益:

    return Attribute.GetCustomAttribute(Member, AttributeType,false); // only look in the current member and don't go up the inheritance tree.
    

    如果您确实需要基于类型进行缓存:

    public static class MyCacheFor<T>
    {
        static MyCacheFor()
        {
            // grab the data
            Value = ExtractExpensiveData(typeof(T));
        }
    
        public static readonly MyExpensiveToExtractData Value;
    
        private static MyExpensiveToExtractData ExtractExpensiveData(Type type)
        {
            // ...
        }
    }
    

    每次都优于字典查找。另外它是线程安全的:)

    干杯, 弗洛里安

    PS:取决于你多久调用一次。在某些情况下,使用反射进行大量序列化确实需要缓存,像往常一样,您想测量性能增益与内存使用量增加的关系。检测您的内存使用情况并分析您的 CPU 时间。

    【讨论】:

    • 我正在通过反射进行序列化,这表明它在某些时候可能值得做。然而,正如这里的每个人所说的那样——在出现问题之前进行优化是没有意义的 :) 干杯
    • 在这种情况下,让我分享一个技巧:如果您要缓存键为类型的内容,请使用泛型类型而不是哈希表。我更新了上面的代码
    • @FlorianDoyon 不错,但如果您在运行时只有一个 System.Type 实例,则无法使用。
    • 当然可以,假设您有 IStaticCache,并且 StaticCache 有一个从 TKey 类型派生值的静态 ctor(例如:更快的枚举 ToString() 实现)然后您可以执行 IStaticCache cache = typeof(StaticTypeCache&lt;&gt;).MakeGeneric(foo) as IStaticCache
    • ConcurrentDictionary 也是线程安全的
    【解决方案2】:

    您可以确定的唯一方法是对其进行分析。如果这听起来像陈词滥调,我很抱歉。但是,一句俗语之所以成为陈词滥调,往往是因为它是真的。

    缓存属性实际上使代码更复杂,更容易出错。因此,您可能需要在决定之前考虑到这一点——您的开发时间。

    所以就像优化一样,除非必须,否则不要这样做。

    根据我的经验(我说的是类似 AutoCAD 的 Windows 应用程序,有很多点击编辑 GUI 操作和繁重的数字运算),自定义属性的读取从来没有——甚至一次——性能瓶颈。

    【讨论】:

    • 唉,我没有可用于正确测试的分析工具。这可能还为时过早,认为它是我的应用程序中相当低级的功能,我想充分利用它。
    • Courtney:您可以通过在重复多次的循环中调用每个实现来进行简单的分析,并测量每个外观运行所需的时间。在这种情况下,您真的不需要探查器。
    【解决方案3】:

    我刚刚遇到了 GetCustomAttributes 成为性能瓶颈的情况。在我的例子中,它在一个有很多行的数据集中被调用了数十万次,这使得问题很容易隔离。缓存属性解决了这个问题。

    初步测试导致在现代机器上调用约 5000 次时性能几乎没有明显下降。 (随着数据集大小的增加,它变得更加明显。)

    我通常同意关于过早优化的其他答案,但是,在 CPU 指令到 DB 调用的规模上,我建议 GetCustomAttributes 更倾向于后者。

    【讨论】:

    • 你是如何缓存这些的?
    • @MikeFlynn 这可能取决于使用情况。但是这个问题的accepted answer 提供了一个起点。
    【解决方案4】:

    您的问题是过早优化的情况。

    您不了解反射类的内部工作原理,因此对多次调用GetCustomAttributes 的性能影响做出假设。该方法本身已经可以很好地缓存其输出,这意味着您的代码实际上会增加开销而不会提高性能。

    节省你的大脑周期来思考你已经知道是问题的事情!

    【讨论】:

    • 我实际上打算在问题中说,但最后编辑出来我不知道它是否在内部这样做。
    • 它应该被命名为“如何优化GetCustomAttributes”,这确实是一个瓶颈。就我而言,我使用了缓存,我的程序启动速度快了 5-6 秒。
    【解决方案5】:

    老问题,但 GetCustomAttributes 代价高昂/重量级

    如果缓存会导致性能问题,则使用缓存可能是个好主意

    我链接的文章:(Dodge Common Performance Pitfalls to Craft Speedy Applications)已被撤下,但这里有一个存档版本的链接:

    https://web.archive.org/web/20150118044646/http://msdn.microsoft.com:80/en-us/magazine/cc163759.aspx

    【讨论】:

      【解决方案6】:

      您真的有性能问题吗?如果没有,请在需要之前不要这样做。

      这可能会有所帮助,具体取决于您使用相同参数调用该方法的频率。如果每个MemberInfoType 组合只调用一次,那么它不会有任何好处。即使你缓存它,你也在用速度换取内存消耗。这可能适合您的应用程序。

      【讨论】:

        猜你喜欢
        • 2018-04-17
        • 2012-03-06
        • 2020-04-22
        • 1970-01-01
        • 2016-08-13
        • 2012-06-05
        • 1970-01-01
        • 2016-01-03
        • 1970-01-01
        相关资源
        最近更新 更多