C#加速字符串?

use*_*191 3 c# string performance

struct mydata
{
    public int id;
    public string data;
}

class Program
{
    static void Main(string[] args)
    {
        List<mydata> myc = new List<mydata>();

        Stopwatch stopwatch = new Stopwatch();

        stopwatch.Start();

        for (int i = 0; i < 1000000; i++)
        {
            mydata d = new mydata();

            d.id = i;
            d.data = string.Format("DataValue {0}",i);

            myc.Add(d);
        }

        stopwatch.Stop();
        Console.WriteLine("End: {0}", stopwatch.ElapsedMilliseconds);
}
Run Code Online (Sandbox Code Playgroud)

这个代码上面的代码是如此慢......?
在较旧的笔记本电脑上,时间是:C#代码高于:1500ms类似的代码在Delphi:450ms ....

然后我将代码更改为KeyValue/Pair(见下文):

Stopwatch stopwatch = new Stopwatch();

        stopwatch.Start();

        var list = new List<KeyValuePair<int , string>>();

        for (int i = 0; i < 1000000; i++)
        {
            list.Add(new KeyValuePair<int,string>(i, "DataValue" + i));
        }

        stopwatch.Stop();
        Console.WriteLine("End: {0}", stopwatch.ElapsedMilliseconds);
        Console.ReadLine();
Run Code Online (Sandbox Code Playgroud)

这改善了1150ms的时间..

如果我删除'+ i',则时间<300ms

如果我尝试用StringBuilder替换它,时间是类似的.

        StringBuilder sb = new StringBuilder();
        Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();

        var list = new List<KeyValuePair<int, string>>();

        for (int i = 0; i < 1000000; i++)
        {
            sb.Append("DataValue");
            sb.Append(i);
            list.Add(new KeyValuePair<int, string>(i, sb.ToString()));
            sb.Clear();
        }

        stopWatch.Stop();
        Console.WriteLine("End: {0}", stopWatch.ElapsedMilliseconds);
        Console.ReadLine();
Run Code Online (Sandbox Code Playgroud)

稍微好一点..如果你删除sb.Append(i)它非常快..

看来,任何时候你必须将一个Int添加到一个字符串/ stringbuilder它非常慢.

我能以任何方式加快速度吗?

编辑**

以下代码是我提出建议后最快的代码:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.Threading;

namespace ConsoleApplication1 { struct mydata { public int id; public string data; }

class Program
{
    static void Main(string[] args)
    {
        List<mydata> myc = new List<mydata>();

        Stopwatch stopwatch = new Stopwatch();

        stopwatch.Start();

        for (int i = 0; i < 1000000; i++)
        {
           mydata d = new mydata();
           d.id = i;
           d.data = "DataValue " + i.ToString();
           myc.Add(d);
        }

        stopwatch.Stop();
        Console.WriteLine("End: {0}", stopwatch.ElapsedMilliseconds);
        Console.ReadLine();
    }

}
Run Code Online (Sandbox Code Playgroud)

}

如果我更换线路:


  d.data = "DataValue " + i.ToString();
有:

  d.data = "DataValue ";

在我的家用机器上,这是从660ms - > 31ms ..

是的..用'+ i.ToString()'慢了630ms

但仍然比拳击/ string.format等快2倍..


            Stopwatch stopwatch = new Stopwatch();

        stopwatch.Start();

        var list = new List<KeyValuePair<int, string>>();

        for (int i = 0; i < 1000000; i++)
        {
            list.Add(new KeyValuePair<int, string>(i, "DataValue" +i.ToString()));
        }

        stopwatch.Stop();
        Console.WriteLine("End: {0}", stopwatch.ElapsedMilliseconds);
        Console.ReadLine();
Run Code Online (Sandbox Code Playgroud)

是612ms ..(如果列表>(1000000),则没有速度差异;是预先初始化的).

Mar*_*ers 10

前两个示例的问题是必须首先将整数装箱,然后转换为字符串.拳击会导致代码变慢.

例如,在这一行:

d.data = string.Format("DataValue {0}", i);
Run Code Online (Sandbox Code Playgroud)

第二个参数string.Formatobject,导致拳击i.请参阅中间语言代码以确认:

...
box int32
call string [mscorlib]System.String::Format(string, object)
...

同样这段代码:

d.data = "DataValue " + i;
Run Code Online (Sandbox Code Playgroud)

相当于:

d.data = String.Concat("DataValue ", i);
Run Code Online (Sandbox Code Playgroud)

这使用了String.Concat带有类型参数的重载,object所以这又涉及一个装箱操作.这可以在生成的中间语言代码中看到:

...
box int32
call string [mscorlib]System.String::Concat(object, object)
...

为了更好的性能,这种方法避免了拳击:

d.data = "DataValue " + i.ToString();
Run Code Online (Sandbox Code Playgroud)

现在中间语言代码不包含box指令,它使用String.Concat带有两个字符串的重载:

...
call instance string [mscorlib]System.Int32::ToString()
call string [mscorlib]System.String::Concat(string, string)
...