-1

根据下面的单元测试方法,StringBuilder 远比 String.Replace 慢,为什么大家都说 StringBuilder 快呢?我错过了什么吗?

[TestMethod]
public void StringReplace()
{
    DateTime date = DateTime.Now;
    string template = File.ReadAllText("file.txt");
    for (int i = 0; i < 100000; i++)
    {
        template = template.Replace("cat", "book" );
        template = template.Replace("book", "cat"); 
    }
    Assert.Fail((DateTime.Now - date).Milliseconds.ToString()); 
}

[TestMethod]
public void StringBuilder()
{
    DateTime date = DateTime.Now;
    StringBuilder template = new StringBuilder(File.ReadAllText("file.txt"));
    for (int i = 0; i < 100000; i++)
    {
        template.Replace("cat", "book");
        template.Replace("book", "cat"); 
    }
    Assert.Fail((DateTime.Now - date).Milliseconds.ToString());
}

结果如下:

字符串替换 - 335 毫秒

字符串生成器 - 799 毫秒

4

4 回答 4

8

StringBuilder构建字符串的速度更快。更换是一个不同的问题。

例如,以下示例代码:

    [TestMethod]
    public void StringConcat()
    {
        var start = DateTime.Now;

        var s = string.Empty;
        for (int i = 0; i < 100000; i++)
        {
            s += "cat";
        }
        Assert.Fail((DateTime.Now - start).TotalMilliseconds.ToString()); 
    }

    [TestMethod]
    public void StringBuilder()
    {
        var start = DateTime.Now;

        var sb = new StringBuilder();
        for (int i = 0; i < 100000; i++)
        { 
            sb.Append("cat");
        }
        Assert.Fail((DateTime.Now - start).TotalMilliseconds.ToString()); 
    }

对我来说,我分别得到 14,645 毫秒(14.6 秒)和 2 毫秒。

于 2013-08-20T19:01:52.680 回答
3

根据几个测试(底部有更多测试的链接)以及我自己的一个快速而草率的测试,String.Replace 的性能优于 StringBuilder.Replace。你似乎没有遗漏任何东西。

为了完整起见,这是我的测试代码:

int big = 500;
String s;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 100; ++i)
{
    sb.Append("cat mouse");
}
s = sb.ToString();

Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < big; ++i)
{ 
    s = s.Replace("cat", "moo"); 
    s = s.Replace("moo", "cat"); 
}
sw.Stop(); Trace.WriteLine(sw.ElapsedMilliseconds); sw.Reset(); sw.Start();
for (int i = 0; i < big; ++i)
{
    sb.Replace("cat", "moo");
    sb.Replace("moo", "cat");
}
sw.Stop(); Trace.WriteLine(sw.ElapsedMilliseconds); sw.Reset(); sw.Start();
for (int i = 0; i < big; ++i)
{
    s = s.Replace("cat", "mooo");
    s = s.Replace("mooo", "cat");
}
sw.Stop(); Trace.WriteLine(sw.ElapsedMilliseconds); sw.Reset(); sw.Start();
for (int i = 0; i < big; ++i)
{
    sb.Replace("cat", "mooo");
    sb.Replace("mooo", "cat");
}
sw.Stop(); Trace.WriteLine(sw.ElapsedMilliseconds);

在我的机器上的输出是:

9
11
7
1977

[编辑]

我错过了一个非常重要的案例。这就是每次将字符串替换为其他内容的情况。这可能很重要,因为 C# 处理字符串的方式。下面是测试缺失案例的代码,以及我系统上的结果。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
class Program
{
    static void Main()
    {
        var repl = GenerateRandomStrings(4, 500);
        String s;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 100; ++i)
        {
            sb.Append("cat mouse");
        }
        s = sb.ToString();
        Stopwatch sw = new Stopwatch();
        sw.Start();
        foreach (string str in repl)
        {
            s = s.Replace("cat", str);
            s = s.Replace(str, "cat");
        }
        sw.Stop(); Trace.WriteLine(sw.ElapsedMilliseconds); sw.Reset(); sw.Start();
        foreach (string str in repl)
        {
            sb.Replace("cat", str);
            sb.Replace(str, "cat");
        }
        sw.Stop(); Trace.WriteLine(sw.ElapsedMilliseconds);
    }

    static HashSet<string> GenerateRandomStrings(int length, int amount)
    {
        HashSet<string> strings = new HashSet<string>();
        while (strings.Count < amount)
            strings.Add(RandomString(length));           
        return strings;
    }

    static Random rnd = new Random();
    static string RandomString(int length)
    {
        StringBuilder b = new StringBuilder();
        for (int i = 0; i < length; ++i)
            b.Append(Convert.ToChar(rnd.Next(97, 122)));
        return b.ToString();
    }
}

输出:

8
1933

然而,随着我们开始增加随机字符串的长度,StringBuilder 解决方案越来越接近 String 解决方案。对于长度为 1000 个字符的随机字符串,我的结果是

138
328

在旧测试中使用这些新知识,当增加要替换的字符串的长度时,我得到了类似的结果。当替换为一千个“a”字符而不是“mooo”的字符串时,我对原始答案的结果变为:

8
11
160
326

尽管结果确实变得更接近了,但对于任何现实世界的使用,String.Replace 似乎仍然胜过 StringBuilder.Replace。

于 2013-08-20T19:19:14.900 回答
0

StringBuilder 更快地连接字符串:

"abc" + "cde" 意味着创建一个新字符串 "abccde" 将所有信息 "abc" 和 "cde" 复制到新字符串

使用 stringbuilder 您只需添加文本即可将“abc”与“cde”连接起来,因此无需创建新类并复制所有信息

replace 函数需要一个字符串才能工作,因此 stringbuilder 的每次迭代都必须创建字符串、替换和重新生成 stringbuilder 类

于 2013-08-20T18:54:43.370 回答
-3

StringBuilder 对于 2+ 个字符串更快。当您只需要连接 2 个字符串时,实际上执行 + 更快。

于 2013-08-20T19:04:35.867 回答