【发布时间】:2013-01-24 14:08:12
【问题描述】:
为 .Net Core 2.1 的发布而编辑
重复测试.Net Core 2.1的发布,我得到这样的结果
“Concat”的 1000000 次迭代耗时 842 毫秒。
“新字符串”的 1000000 次迭代耗时 1009 毫秒。
“sb”的 1000000 次迭代耗时 902 毫秒。
简而言之,如果您使用的是 .Net Core 2.1 或更高版本,Concat 为王。
我已编辑该问题以纳入 cmets 中提出的有效点。
我在沉思my answer to a previous question,我开始怀疑,这是不是,
return new string(charSequence.ToArray());
将IEnumerable<char> 转换为string 的最佳方式。我做了一些搜索,发现这个问题已经问过here。该答案断言,
string.Concat(charSequence)
是更好的选择。在回答了这个问题之后,还建议使用StringBuilder 枚举方法,
var sb = new StringBuilder();
foreach (var c in chars)
{
sb.Append(c);
}
return sb.ToString();
虽然这可能有点笨拙,但为了完整起见,我将其包含在内。我决定我应该做一个小测试,使用的代码在底部。
当在发布模式下构建,经过优化,并在没有附加调试器的情况下从命令行运行时,我会得到这样的结果。
“Concat”的 1000000 次迭代耗时 1597 毫秒。
“新字符串”的 1000000 次迭代耗时 869 毫秒。
“sb”的 1000000 次迭代耗时 748 毫秒。
据我估计,new string(...ToArray()) 的速度几乎是string.Concat 方法的两倍。 StringBuilder 仍然稍微快一些,但使用起来很尴尬,但可以作为扩展。
我应该坚持使用new string(...ToArray()),还是我缺少什么?
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
class Program
{
private static void Main()
{
const int iterations = 1000000;
const string testData = "Some reasonably small test data";
TestFunc(
chars => new string(chars.ToArray()),
TrueEnumerable(testData),
10,
"new String");
TestFunc(
string.Concat,
TrueEnumerable(testData),
10,
"Concat");
TestFunc(
chars =>
{
var sb = new StringBuilder();
foreach (var c in chars)
{
sb.Append(c);
}
return sb.ToString();
},
TrueEnumerable(testData),
10,
"sb");
Console.WriteLine("----------------------------------------");
TestFunc(
string.Concat,
TrueEnumerable(testData),
iterations,
"Concat");
TestFunc(
chars => new string(chars.ToArray()),
TrueEnumerable(testData),
iterations,
"new String");
TestFunc(
chars =>
{
var sb = new StringBuilder();
foreach (var c in chars)
{
sb.Append(c);
}
return sb.ToString();
},
TrueEnumerable(testData),
iterations,
"sb");
Console.ReadKey();
}
private static TResult TestFunc<TData, TResult>(
Func<TData, TResult> func,
TData testData,
int iterations,
string stage)
{
var dummyResult = default(TResult);
var stopwatch = Stopwatch.StartNew();
for (var i = 0; i < iterations; i++)
{
dummyResult = func(testData);
}
stopwatch.Stop();
Console.WriteLine(
"{0} iterations of \"{2}\" took {1}ms.",
iterations,
stopwatch.ElapsedMilliseconds,
stage);
return dummyResult;
}
private static IEnumerable<T> TrueEnumerable<T>(IEnumerable<T> sequence)
{
foreach (var t in sequence)
{
yield return t;
}
}
}
【问题讨论】:
-
1.) 如果这是在调试模式下完成的,结果是不准确的,必须扔掉。 2.) 这听起来像premature optimization。如果它没有导致性能下降(我敢肯定它没有),那么测试性能可以解决什么问题?
-
旁注:考虑测试真实的
IEnumerable(即Enumerable.Repeat('d', 100))以避免构造函数/转换方法中的潜在捷径。 -
要添加到@DaveZych 评论,您需要在发布模式下测试不附加调试器:在Visual Studio 中按Ctrl+F5。
-
@JimMischel,你说得很好,我已经在发布模式下进行了测试,没有附加调试器以获得我所说的结果。
-
@DaveZych, 1) 请参阅我之前的回复。 2) 考试的目的是回答问题。考虑到许多易于使用的选择,速度或性能是一个糟糕的差异化因素吗?
标签: c# performance