代码之家  ›  专栏  ›  技术社区  ›  JL. Hans Passant

C-是否需要像在javascript中那样缩短查找链?

  •  4
  • JL. Hans Passant  · 技术社区  · 15 年前

    我有一个有公共财产的班级。在一个函数中,我引用这个属性大约30-40次。

      this.MyProp; 
    

    在函数中定义局部变量会更好吗?,

     string myProp = this.MyProp;
    

    这样做之后-在函数中,我缩短了查找链…所以我只需要提到我的道具,而不是这个。

    在JavaScript中,缩短查找时间确实提高了性能。在C中会更好/更差吗?因为很明显,我还需要创建另一个局部字符串变量。

    6 回复  |  直到 15 年前
        1
  •  11
  •   Community Reversed Engineer    7 年前

    从纯性能的角度来看,这取决于属性正在做什么。如果 MyProp getter只返回一个私有字段,开销完全无关紧要。事实上,除非你明显在做一些重要的事情,比如大量的枚举或者调用数据库,否则这是没有关系的。担心这是微观优化。

    但是,需要注意的是属性的用途,即通过封装的例程强制访问值,以确保一致性。如果您试图绕过这一点,您将使代码面临更大的错误风险。

    来自@davidandres评论:

    根据惯例,属性通常不应该在getter或setter中执行任何实质性的操作。所以我想说,如果您只是通过反射镜或文档或查看自己的代码来验证属性的行为是否良好,那就没有关系了。处理那些明确需要本地化的值的情况应该是一个边缘情况,在验证了它是必要的之后。

    编辑:要明确的是,我不建议您出于任何性能原因通常避免使用本地值。AS @Guffa 注意到影响是微不足道的 无论哪种方式 . 我指出,属性通常是有原因的属性,默认情况下,对值的访问应该通过属性进行。

        2
  •  1
  •   Guffa    15 年前

    不要害怕声明局部变量,它几乎是免费的。在32位系统上,字符串变量将使用四个字节的堆栈空间。总是创建分配局部变量的堆栈帧,因此分配该变量不需要额外的执行时间。

    但是,无论您是否应该使用局部变量,都应该基于更正确的情况。除非您有一个循环,在这个循环中,您使用的值大约是1000次或更多,否则性能差异甚至很难测量。

    (当然,这是基于这样一个假设,即房产得到了正确的实施,因此阅读起来并不昂贵。)

        3
  •  0
  •   Community Reversed Engineer    7 年前

    通常不需要“this.”来引用同一类中的属性或字段。只有在命名冲突时才使用它。微软 naming guidelines 避免冲突,所以我不使用它。:)

    作为旁白,如果有一个方法引用属性30-40次,则很可能 Long Method 嗅觉。

    编辑:我不打算为了“这个”的使用而发动宗教战争。( See Do you prefix your instance variable with ‘this’ in java ? )在我们的公司中,我们在字段前面加上下划线(这是另一个热门话题);再加上我们的(非匈牙利语)命名约定,很明显哪些是属性。用 ReSharper 我们甚至可以做一些不同的事情,比如颜色代码参数。 亲自 我觉得“这”是噪音,并按照Resharper的建议删除它。

    最后我坚持我的回答。而我看重可读性 高度地 ,如果您不能快速、轻松地确定一个方法在做什么(这个或不这个),那么它可能太长了。

        4
  •  0
  •   Community Reversed Engineer    7 年前

    对于一个简单的函数和正则属性,这一点都不应该让您担心。
    这似乎是个很好的问题 lambda表达式 不过,快速测试表明,在这种情况下,如果您对属性有很多引用(这与所做的类似),那么它可能是值得的。 here ):

    class Program
    {
        public static int Property { get; set; }
    
        static void Main(string[] args)
        {
            Property = 3;
            int mainVar = Property;
    
            for (int run = 0; run < 5; run++)
            {
                Stopwatch s = new Stopwatch();
                Action useProperty = () =>
                {
                    double res;
                    for (int counter = 0; counter < 10000000; counter++)
                        res = Math.Cos(Property);
                };
                s.Start();
                useProperty();
                Console.WriteLine("Property Direct   : {0}", s.Elapsed);
                s.Reset();
    
                Action useMainVar = () =>
                {
                    double res;
                    for (int counter = 0; counter < 10000000; counter++)
                        res = Math.Cos(mainVar);
                };
                s.Start();
                useProperty();
                Console.WriteLine("Variable from Main: {0}", s.Elapsed);
                s.Reset();
    
                Action useLocalVariable = () =>
                {
                    int j = Property;
                    double res;
                    for (int counter = 0; counter < 10000000; counter++)
                        res = Math.Cos(j);
                };
                s.Start();
                useLocalVariable();
                Console.WriteLine("Lambda Local      : {0}", s.Elapsed);
                Console.WriteLine();
            }
            Console.ReadKey();
        }
    }
    

    结果:

    Property Direct   : 00:00:00.6410370
    Variable from Main: 00:00:00.6265704
    Lambda Local      : 00:00:00.2793338
    
    Property Direct   : 00:00:00.6380671
    Variable from Main: 00:00:00.6354271
    Lambda Local      : 00:00:00.2798229
    
    Property Direct   : 00:00:00.6337640
    Variable from Main: 00:00:00.6280359
    Lambda Local      : 00:00:00.2809130
    
    Property Direct   : 00:00:00.6286821
    Variable from Main: 00:00:00.6254493
    Lambda Local      : 00:00:00.2813175
    
    Property Direct   : 00:00:00.6279096
    Variable from Main: 00:00:00.6282695
    Lambda Local      : 00:00:00.2783485
    
        5
  •  0
  •   codymanix    15 年前

    大多数较小的属性都是由JIT自动内联的,因此没有太多的性能增益。

    对于非常重要的属性,在缩短查找链时确实可以节省时间。不允许优化器删除多余的调用,因为它无法确定它们是否有副作用,否则它将更改程序的语义。

    有一个例外,即不应将属性值保存到本地:

    for (int i=0; i<myArray.Length; i++) { /* do something with myArray[i] */ }
    

    此模式由JIT识别,它将自动删除数组访问边界测试。

    但如果你这样做:

    int len = myArray.Length;
    for (int i=0; i<len; i++) { /* do something with myArray[i] */ }
    

    然后无法删除边界测试,因为优化器无法确定是否可以使用变量len进行调节。

    所以在你“优化”之前要三思。

        6
  •  -1
  •   Akash Kava    15 年前

    我做了性能计算,但是它很小,但是每增加一个小的位都可以在CPU周期上获得巨大的收益,因为您在Web服务器、网络活动等中执行代码100次。

    C# Local Variable Caching Statistics 您还可以下载代码并使用它进行播放。