初始化循环内部或外部的字符串的效率

时间:2014-03-24 13:32:58

标签: c# string performance memory-management

在C#控制台应用程序中,我有一个循环,它遍历集合中的大约8000个项目,设置大约八个字符串等于项目的各种属性,然后使用这些字符串执行各种其他操作。为了保持我的代码有条理,我提前声明所有字符串并将它们保留为空,直到读取一个项目并且循环将相应的字符串设置为等于适当的值。我的问题是,在声明循环外的字符串与内部之间是否存在明显的性能差异?我知道它会在技术上耗费一些额外的时钟周期,每次循环迭代时声明它们,并且在8000次迭代之后可能会开始累加,但我不知道它有多少甚至是否重要?这个应用程序已经花了半个小时来完成它的完整周期,所以几秒钟的差异是微不足道的,但是如果我们谈论分钟显然这是一件坏事。

请记住,这主要是好奇心的问题,我可以诚实地在不影响应用程序的地方声明这些变量。我确信最佳实践表明他们应该总是在循环之外,但我总是想知道它在这种低影响力操作中真正产生了多大的差异。

3 个答案:

答案 0 :(得分:1)

  

我的问题是,在声明循环外的字符串与内部字符串之间会有明显的性能差异吗?

不,不会。你重新初始化循环中的字符串。如果您正在通过在循环外部初始化代码然后在内部再次执行它来使程序执行更多工作。我猜想编译器会优化它。

  

我知道它会在技术上耗费一些额外的时钟周期,每次循环迭代时都会声明它们

您应该让编译器完成它的工作并为您优化它。尝试编译器的工作只会让您感到沮丧,并使优化代码变得更加困难。这很可能完全是不真实的。

答案 1 :(得分:1)

首先,对于现代计算机而言,8000是相对较小的数字,所以我不会担心声明变量或使用属性等小事,因为差异可以忽略不计。我认识一位同事在我们优化我们的代码时,坚持要求消除属性的使用。我一直告诉他,他把时间浪费在可以忽略不计的事情上,但他成功地说服了团队,他们在没有我的情况下进行了测试。循环有100万次迭代,但差异几乎不到半秒。

现在在你的情况下,我相信实际上根本没有任何区别。而且,8000太小了,甚至不用考虑差异,如果存在的话。

至于最佳实践,它实际上是另一种方式。范围应尽可能小,因此在循环中声明它们。

这是一个很好的test done by one of the SO users,有充分的讨论。

答案 2 :(得分:1)

没有任何区别(好吧,不应该)。至少,你甚至不应该考虑它 - 编译器优化会为你做。

基本上,当您为变量分配新的字符串值时,会发生以下情况:

  • 在堆中创建的新字符串(除非它是实例化的 - 为简单起见,我们跳过它)
  • 在旧字符串引用(堆栈中的引用变量)中复制的新字符串引用
  • 现在,任何人都不会引用旧字符串,因此稍后将由垃圾收集器收集

如果你在循环或外部循环中声明变量,那么确实不重要 - 编译器(最有可能)只会重复使用相同的堆栈区域来保持对字符串的引用。

最佳做法是在最内部范围内声明变量,即在您的情况下在内部循环中。

修改

添加一些练习。考虑以下示例(注意我必须编写多少代码,以便优化器至少为我们留下一些东西):

internal class Program
{
    private static string InnerLoop()
    {
        var sb = new StringBuilder();

        string s;
        for (int i = 0; i < 8000; i++)
        {
            s = i.ToString();
            sb.Append(s);
        }

        return sb.ToString();
    }

    private static string OuterLoop()
    {
        var sb = new StringBuilder();

        for (int i = 0; i < 8000; i++)
        {
            string s;
            s = i.ToString();
            sb.Append(s);
        }

        return sb.ToString();
    }

    private static void Main(string[] args)
    {
        Console.WriteLine(InnerLoop());
        Console.WriteLine(OuterLoop());
    }
}

Build in Release,使用Reflector打开并查看正在运行的编译器优化:

enter image description here

您可以用类似的方式玩代码。