简体   繁体   English

为什么StringBuilder.Replace比String.Replace慢

[英]Why StringBuilder.Replace is slower than String.Replace

According to the following unit test methods, StringBuilder is far slower than String.Replace, how come every one saying StringBuilder is faster? 根据以下单元测试方法,StringBuilder比String.Replace慢得多,为什么每个人都说StringBuilder更快? Am I missing something? 我想念什么吗?

[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());
}

Here is the result: 结果如下:

StringReplace - 335ms StringReplace-335ms

StringBuilder - 799ms StringBuilder-799毫秒

StringBuilder is faster at building strings. StringBuilder 构建字符串的速度更快。 Replacing is a different concern. 更换是另一个问题。

Eg, the following example code: 例如,以下示例代码:

    [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()); 
    }

For me, I get 14,645ms (14.6 seconds) and 2ms respectively. 对我来说,我分别获得了14,645ms(14.6秒)和2ms。

According to several tests (links to more tests at the bottom) as well as a quick and sloppy test of my own, String.Replace performs better than StringBuilder.Replace. 根据一些测试 (在底部有更多测试的链接)以及我自己的快速而草率的测试,String.Replace的性能优于StringBuilder.Replace。 You do not seem to be missing anything. 您似乎没有丢失任何东西。

For completeness sake, here's my testing code: 为了完整起见,这是我的测试代码:

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);

The output, on my machine, is: 在我的机器上,输出为:

9
11
7
1977

[EDIT] [编辑]

I missed one very important case. 我错过了一个非常重要的案例。 That is the case where every time the string is replaced with something else. 每次将字符串替换为其他字符串时就是这种情况。 This could matter because of the way C# handles strings. 这可能很重要,因为C#处理字符串的方式。 What follows is the code that tests the missing case, and the results on my system. 接下来是测试遗漏情况的代码以及系统中的结果。

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();
    }
}

Output: 输出:

8
1933

However, as we start to increase the length of the random strings, the StringBuilder solution comes closer and closer to the String solution. 但是,随着我们开始增加随机字符串的长度,StringBuilder解决方案越来越接近String解决方案。 For random strings with a length of 1000 characters, my results are 对于长度为1000个字符的随机字符串,我的结果是

138
328

Using this new knowledge on the old tests, I get similar results when increasing the length of the string to replace with. 使用旧测试中的新知识,增加要替换的字符串的长度时,我会得到类似的结果。 When replacing with a string that is a thousand 'a' characters instead of "mooo", my results for the original answer become: 当用一千个“ a”字符而不是“ mooo”代替字符串时,原始答案的结果是:

8
11
160
326

Although the results do become closer, it still seems that for any real world use, String.Replace beats StringBuilder.Replace. 尽管结果确实越来越接近,但对于任何实际使用而言,String.Replace似乎都胜过StringBuilder.Replace。

StringBuilder is fastern to concatenate strings: StringBuilder可以更快地连接字符串:

"abc" + "cde" implies creating a new string "abccde" copying all information "abc" and "cde" to the new string “ abc” +“ cde”表示创建一个新字符串“ abccde”,将所有信息“ abc”和“ cde”复制到新字符串

With stringbuilder you concatenate "abc" with "cde" just adding the text, so there is no need to create a new class and copy all information 使用stringbuilder,只需添加文本即可将“ abc”与“ cde”连接起来,因此无需创建新类并复制所有信息

The replace function need a string to work, so each iteration of stringbuilder have to create the string, replace, and regenerate the stringbuilder class replace函数需要一个字符串才能工作,因此stringbuilder的每次迭代都必须创建该字符串,替换并重新生成stringbuilder类。

StringBuilder is faster for 2+ strings. 对于2个以上的字符串,StringBuilder速度更快。 When you only need to concatenate 2 strings, actually doing + is faster. 当您只需要连接2个字符串时,实际上+会更快。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM