我在Windows 10 64位操作系统上使用.net core 2.0.5。每次,我都会使用string.Concat或string.Format来连接字符串,因为我学会了使用string" abc" +" def"表现更差。 (内存使用是一个不同的主题。) - 我最近对字符串连接进行了基准测试,但结果非常有趣;
using System;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Columns;
using BenchmarkDotNet.Attributes.Exporters;
namespace TryBenchmark.ConsoleApp.Benchmarks
{
[RPlotExporter, RankColumn]
public class StringConcatVsStringFormat
{
[Benchmark]
public void StringConcat001()
{
string result = "test1 " + "test2 " + "test3";
if (result != "test1 test2 test3")
{
throw new InvalidOperationException("Tests are faulty !");
}
}
[Benchmark]
public void StringConcat002()
{
string result = String.Concat("test1 ", "test2 ", "test3");
if (result != "test1 test2 test3")
{
throw new InvalidOperationException("Tests are faulty !");
}
}
[Benchmark]
public void StringConcat003()
{
string name1 = "test1";
string name2 = "test2";
string name3 = "test3";
string result = $"{name1} {name2} {name3}";
if (result != "test1 test2 test3")
{
throw new InvalidOperationException("Tests are faulty !");
}
}
[Benchmark]
public void StringFormat()
{
string result = String.Format("{0} {1} {2}", "test1", "test2", "test3");
if (result != "test1 test2 test3")
{
throw new InvalidOperationException("Tests are faulty !");
}
}
}
}
结果;
StringConcatVsStringFormat.StringFormat: DefaultJob
Runtime = .NET Core 2.0.5 (CoreCLR 4.6.26020.03, CoreFX 4.6.26018.01), 64bit RyuJIT; GC = Concurrent Workstation
Mean = 149.2378 ns, StdErr = 0.9310 ns (0.62%); N = 79, StdDev = 8.2749 ns
Min = 140.0365 ns, Q1 = 143.8430 ns, Median = 145.9400 ns, Q3 = 150.4091 ns, Max = 172.1811 ns
IQR = 6.5661 ns, LowerFence = 133.9939 ns, UpperFence = 160.2582 ns
ConfidenceInterval = [146.0541 ns; 152.4215 ns] (CI 99.9%), Margin = 3.1837 ns (2.13% of Mean)
Skewness = 1.29, Kurtosis = 3.57, MValue = 2
-------------------- Histogram --------------------
[139.525 ns ; 142.434 ns) | @@@@@@@@@@@
[142.434 ns ; 145.809 ns) | @@@@@@@@@@@@@@@@@@@@@@@@@@@@
[145.809 ns ; 150.658 ns) | @@@@@@@@@@@@@@@@@@@@@@
[150.658 ns ; 156.460 ns) | @@@@
[156.460 ns ; 160.840 ns) | @
[160.840 ns ; 164.215 ns) | @@@@@@@
[164.215 ns ; 169.531 ns) | @@@@
[169.531 ns ; 173.869 ns) | @@
---------------------------------------------------
Total time: 00:03:26 (206.65 sec)
// * Summary *
BenchmarkDotNet=v0.10.14, OS=Windows 10.0.16299.248 (1709/FallCreatorsUpdate/Redstone3)
Intel Core i7-7500U CPU 2.70GHz (Kaby Lake), 1 CPU, 4 logical and 2 physical cores
Frequency=2835939 Hz, Resolution=352.6169 ns, Timer=TSC
.NET Core SDK=2.1.100
[Host] : .NET Core 2.0.5 (CoreCLR 4.6.26020.03, CoreFX 4.6.26018.01), 64bit RyuJIT [AttachedDebugger]
DefaultJob : .NET Core 2.0.5 (CoreCLR 4.6.26020.03, CoreFX 4.6.26018.01), 64bit RyuJIT
Method | Mean | Error | StdDev | Median | Rank |
---------------- |-----------:|----------:|----------:|------------:|-----:|
StringConcat001 | 1.043 ns | 0.0608 ns | 0.1558 ns | 0.9972 ns | 1 |
StringConcat002 | 26.680 ns | 0.5303 ns | 0.5445 ns | 26.7079 ns | 2 |
StringConcat003 | 143.028 ns | 2.4180 ns | 2.2618 ns | 143.9356 ns | 3 |
StringFormat | 149.238 ns | 3.1837 ns | 8.2749 ns | 145.9400 ns | 4 |
// * Warnings *
Environment
Summary -> Benchmark was executed with attached debugger
StringConcat001如何最快?
难道我做错了什么?或者我错误配置了benchmarkdotnet?
答案 0 :(得分:4)
C#编译器非常智能,可以检测到string result = "test1 " + "test2 " + "test3";
的值是常量。
您可以使用ILSpy查看编译器生成的内容:
[Benchmark]
public void StringConcat001()
{
if (!("test1 test2 test3" != "test1 test2 test3"))
{
return;
}
throw new InvalidOperationException("Tests are faulty !");
}
要欺骗编译器,您必须将这些值放到公共的非只读字段中,或者将它们用作给定方法的参数。 BenchmarkDotNet 0.10.14
允许您提供值arguments。
[RPlotExporter, RankColumn]
[MarkdownExporterAttribute.StackOverflow]
[MemoryDiagnoser]
public class StringConcatVsStringFormat
{
[Benchmark]
[Arguments("test1 ", "test2 ", "test3")]
public string StringConcat001(string arg1, string arg2, string arg3)
=> arg1 + arg2 + arg3;
[Benchmark]
[Arguments("test1 ", "test2 ", "test3")]
public string StringConcat002(string arg1, string arg2, string arg3)
=> String.Concat(arg1, arg2, arg3);
[Benchmark]
[Arguments("test1 ", "test2 ", "test3")]
public string StringConcat003(string arg1, string arg2, string arg3)
=> $"{arg1} {arg2} {arg3}";
[Benchmark]
[Arguments("test1 ", "test2 ", "test3")]
public string StringFormat(string arg1, string arg2, string arg3)
=> string.Format("{0} {1} {2}", arg1, arg2, arg3);
}
在我的电脑上提供以下结果:
BenchmarkDotNet=v0.10.14, OS=Windows 10.0.16299.309 (1709/FallCreatorsUpdate/Redstone3)
Intel Xeon CPU E5-1650 v4 3.60GHz, 1 CPU, 12 logical and 6 physical cores
Frequency=3507503 Hz, Resolution=285.1031 ns, Timer=TSC
[Host] : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2633.0
DefaultJob : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.7.2633.0
Method | arg1 | arg2 | arg3 | Mean | Error | StdDev | Rank | Gen 0 | Allocated |
---------------- |------- |------- |------ |----------:|----------:|----------:|-----:|-------:|----------:|
StringConcat001 | test1 | test2 | test3 | 25.95 ns | 0.1755 ns | 0.1642 ns | 2 | 0.0091 | 48 B |
StringConcat002 | test1 | test2 | test3 | 25.66 ns | 0.3480 ns | 0.3085 ns | 1 | 0.0091 | 48 B |
StringConcat003 | test1 | test2 | test3 | 112.32 ns | 0.9539 ns | 0.8923 ns | 4 | 0.0098 | 52 B |
StringFormat | test1 | test2 | test3 | 111.62 ns | 0.9982 ns | 0.8849 ns | 3 | 0.0098 | 52 B |