簡體   English   中英

為什么StringBuilder.Replace比String.Replace慢

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

根據以下單元測試方法,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());
}

結果如下:

StringReplace-335ms

StringBuilder-799毫秒

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,645ms(14.6秒)和2ms。

根據一些測試 (在底部有更多測試的鏈接)以及我自己的快速而草率的測試,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。

StringBuilder可以更快地連接字符串:

“ abc” +“ cde”表示創建一個新字符串“ abccde”,將所有信息“ abc”和“ cde”復制到新字符串

使用stringbuilder,只需添加文本即可將“ abc”與“ cde”連接起來,因此無需創建新類並復制所有信息

replace函數需要一個字符串才能工作,因此stringbuilder的每次迭代都必須創建該字符串,替換並重新生成stringbuilder類。

對於2個以上的字符串,StringBuilder速度更快。 當您只需要連接2個字符串時,實際上+會更快。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM