变量范围:实例化内部或外部循环

时间:2014-08-22 08:56:06

标签: c# .net performance instantiation

通过我昨天发布的一个问题,很明显,在循环之外声明一个变量并在其中实例化它没有性能优势,只需将声明移动到循环内部,因此声明和实例化同时完成。但实例化呢?请考虑以下两个选项。

//OPTION 1:
while (_doWork)
{
    Person p = new Person(name = "John", age = 35);
    //work that involves reading (not writing to) p
}

//OPTION 2:
Person p = new Person(name = "John", age = 35);
while (_doWork)
{
    //work that involves reading (not writing to) p
}

就本问题而言,关键假设是:

    在循环之外不需要
  1. p
  2. p 也没有写入(因此结果明智,两者是相同的)
  3. 没有结果理由说明为什么我们应该继续重新实例化 p p 在两个选项中看起来都相同)
  4. 问题:哪种情况更好,哪种选择更好?

    这篇文章的答案(尽管是关于声明,而不是实例化)似乎表明了后者:Declaring variables inside or outside of a loop

    我的想法:

    • 对我来说,重新实现它似乎是一个很大的浪费。对于原始类型可能没问题,但是对于复杂的类?
    • int a = 0与int a = new int()相同,所以我猜上面的答案也适用于原始类型?

2 个答案:

答案 0 :(得分:3)

  

哪种表现更好,哪种选择更好?

根据您的问题,如果只需要一个Person实例,那么没有合理的理由将其反复实施 在循环内。在循环外部分配一次并在内部使用。

关于基本类型,您应该区分值类型(intlongdouble)和引用类型(string)。值类型在堆栈上分配,而引用类型在堆上分配。因此,对于Person类,我们必须在堆内分配适当的字节数,而在堆栈上分配int是一个更快的分配。

除了最佳做法之外,如果您想知道两者中哪一个具有更好的性能,请对代码进行基准测试。这是在我的英特尔酷睿i5 M430上使用.NET Framework 4.5,VS2013在Debug Mode中运行的输出:

public class Person
{
    public Person(string name, int age)
    {
        Age = age;
        Name = name;
    }

    public int Age { get; set; }
    public string Name { get; set; }
}

private static void Main(string[] args)
{
   Stopwatch sw = new Stopwatch();
   sw.Start();
   for (int i = 0; i < 1000000; i++)
   {
      Person p = new Person("John", 35);
      var age = p.Age;
      var name = p.Name;
   }

   Console.WriteLine("Loop with inner allocation took {0}", m sw.Elapsed);

   sw.Restart();
   Person px = new Person("John", 35);

   for (int i = 0; i < 1000000; i++)
   {
      var age = px.Age;
      var name = px.Name;
   }

   Console.WriteLine("Loop with outter allocation took {0}", sw.Elapsed)
}

结果:

Loop with inner allocation took 00:00:00.0708861
Loop with outter allocation took 00:00:00.0155522

答案 1 :(得分:1)

如果你做了10次,那么它的性能要低于你只做一次,因此单个实​​例化效率更高。如果您只需要一个实例,那么将对象初始化为多个时间也是没有意义的。这也可能有副作用,可能会使事情变得更糟。

因此,如果循环中没有改变,那么总是在循环之外声明并初始化它。这也将提高可读性,因为每个人都可以立即看到此对象很可能在以下循环中不会改变。

Person p = new Person("John", 35);
while (_doWork)
{
    //work that involves reading (not writing to) p
}

如果必须在循环中创建对象,则应在循环中声明它。但不是因为它性能更高,而且更具可读性。

阅读:https://softwareengineering.stackexchange.com/questions/56585/where-do-you-declare-variables-the-top-of-a-method-or-when-you-need-them