根据以下单元测试方法,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 - 799ms
答案 0 :(得分:7)
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毫秒。
答案 1 :(得分:3)
根据several tests(链接到底部的更多测试)以及对我自己的快速和草率测试,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 beats StringBuilder.Replace。
答案 2 :(得分:0)
StringBuilder是连接字符串的紧要选择:
“abc”+“cde”意味着创建一个新字符串“abccde”将所有信息“abc”和“cde”复制到新字符串
使用stringbuilder,只需添加文本即可将“abc”与“cde”连接起来,因此无需创建新类并复制所有信息
replace函数需要一个字符串才能工作,所以stringbuilder的每次迭代都必须创建字符串,替换并重新生成stringbuilder类
答案 3 :(得分:-2)
StringBuilder对于2个以上的字符串更快。当你只需要连接2个字符串时,实际做+更快。