2

我想知道当我选择将一个字符串或单个字符添加到常量字符串时是否会对性能产生影响。

所以我写了一个小控制台应用程序:(.NET 4)

static class Program
{
    const string STR = "string ";

    static void Main()
    {
        var arr = new string[99999999];

        Stopwatch timer = new Stopwatch();

        Console.ReadLine();

        timer.Start();

        //for (uint i = 0; i < 99999999; i++)
        //{
        //  arr[i] = STR + 'C';
        //}

        for (uint i = 0; i < 99999999; i++)
        {
            arr[i] = STR + "C";
        }

        timer.Stop();

        Console.WriteLine(timer.ElapsedMilliseconds);

        Console.ReadLine();
    }
}

您必须评论一个 for 循环。

因此,STR + "C"大约需要 1300 毫秒。

因为STR + 'C'我还没有看到结果。这需要很长时间,似乎很难打扰我的电脑。

所以,我的问题是。这种性能影响如何可能?我知道在实际使用中不会经常出现 99999999 个值的数组,但它仍然是一个巨大的差异。

提前致谢!

4

2 回答 2

6

这实际上很容易解释:您偶然发现了 C# 编译器将对字符串表达式执行常量折叠这一事实。

由于您声明STRconst,因此它具有用文字字符串替换对它的引用的效果"string "。然后,当编译器遇到 时"string " + "C",它会将该表达式替换为等效的"string C"。因此,实际完成的循环将花费所有时间将该字符串分配给数组中的不同位置。

相反,char串联并没有以这种方式进行优化,因此您实际上必须等待串联(包括新string对象的分配)以及数组分配。同样,循环会产生大量垃圾,所以你也在等待收集器。

如果你想公平地比较这两个操作,我会做两件事:

  1. 将声明更改为STRtostatic readonly而不是const.
  2. 减少迭代次数,这样您就可以真正获得完整的运行。
于 2013-07-01T07:54:02.517 回答
4

像这样的简单程序:

var val = "hello ";     
val += 'r'; 

执行一个char值到的装箱object,我们可以从生成的IL

IL_0001:  ldstr       "hello "
IL_0006:  stloc.0     // val
IL_0007:  ldloc.0     // val
IL_0008:  ldc.i4.s    72 
IL_000A:  box         System.Char
IL_000F:  call        System.String.Concat
IL_0014:  stloc.0     // val
IL_0015:  ldloc.0     // val

相反,在 的情况下string,不涉及任何拳击,因此速度明显更快。

那么为什么要执行拳击呢?因为 在其中只有一个是 a 的 2 个参数上调用System.String.Concat(String,String)(这是运算符调用的结果),所以调用 String.Concat(object,object)的重载,所以 的值被装箱能够传递到该方法调用中。binary +stringchar

于 2013-07-01T07:54:00.977 回答