Dam*_*isa 14 c# string optimization performance coding-style
我有一个字符串,周围可能有空格字符,我想检查它是否基本上是空的.
有很多方法可以做到这一点:
1 if (myString.Trim().Length == 0)
2 if (myString.Trim() == "")
3 if (myString.Trim().Equals(""))
4 if (myString.Trim() == String.Empty)
5 if (myString.Trim().Equals(String.Empty))
Run Code Online (Sandbox Code Playgroud)
我知道这通常是过早优化的明显案例,但我很好奇,并且有可能做到这一点足以产生性能影响.
那么哪一个是最有效的方法呢?
有没有更好的方法我没想过?
编辑:此问题的访问者注意事项:
对这个问题进行了一些非常详细的调查 - 特别是来自Andy和Jon Skeet.
如果你在搜索某些内容时偶然发现了这个问题,那么至少阅读Andy和Jon的帖子是非常值得的.
似乎有一些非常有效的方法,最有效的方法取决于我需要处理的字符串的内容.
如果我无法预测字符串(在我的情况下我不能预测),Jon的IsEmptyOrWhiteSpace方法似乎通常更快.
谢谢大家的意见.我将选择安迪的答案作为"正确"的答案仅仅是因为他应该为他所付出的努力赢得声誉,而乔恩已经拥有了十亿美元的声誉.
Pon*_*dum 19
编辑:新测试:
Test orders:
x. Test name
Ticks: xxxxx //Empty String
Ticks: xxxxx //two space
Ticks: xxxxx //single letter
Ticks: xxxxx //single letter with space
Ticks: xxxxx //long string
Ticks: xxxxx //long string with space
1. if (myString.Trim().Length == 0)
ticks: 4121800
ticks: 7523992
ticks: 17655496
ticks: 29312608
ticks: 17302880
ticks: 38160224
2. if (myString.Trim() == "")
ticks: 4862312
ticks: 8436560
ticks: 21833776
ticks: 32822200
ticks: 21655224
ticks: 42358016
3. if (myString.Trim().Equals(""))
ticks: 5358744
ticks: 9336728
ticks: 18807512
ticks: 30340392
ticks: 18598608
ticks: 39978008
4. if (myString.Trim() == String.Empty)
ticks: 4848368
ticks: 8306312
ticks: 21552736
ticks: 32081168
ticks: 21486048
ticks: 41667608
5. if (myString.Trim().Equals(String.Empty))
ticks: 5372720
ticks: 9263696
ticks: 18677728
ticks: 29634320
ticks: 18551904
ticks: 40183768
6. if (IsEmptyOrWhitespace(myString)) //See John Skeet's Post for algorithm
ticks: 6597776
ticks: 9988304
ticks: 7855664
ticks: 7826296
ticks: 7885200
ticks: 7872776
7. is (string.IsNullOrEmpty(myString.Trim()) //Cloud's suggestion
ticks: 4302232
ticks: 10200344
ticks: 18425416
ticks: 29490544
ticks: 17800136
ticks: 38161368
Run Code Online (Sandbox Code Playgroud)
并使用的代码:
public void Main()
{
string res = string.Empty;
for (int j = 0; j <= 5; j++) {
string myString = "";
switch (j) {
case 0:
myString = "";
break;
case 1:
myString = " ";
break;
case 2:
myString = "x";
break;
case 3:
myString = "x ";
break;
case 4:
myString = "this is a long string for testing triming empty things.";
break;
case 5:
myString = "this is a long string for testing triming empty things. ";
break;
}
bool result = false;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i <= 100000; i++) {
result = myString.Trim().Length == 0;
}
sw.Stop();
res += "ticks: " + sw.ElapsedTicks + Environment.NewLine;
}
Console.ReadKey(); //break point here to get the results
}
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 15
(编辑:有关该方法的不同微优化的基准,请参见帖子的底部)
不要修剪它 - 这可能会创建一个你实际上不需要的新字符串.相反,请查看字符串中是否有任何不是空格的字符(无论您想要什么样的定义).例如:
public static bool IsEmptyOrWhitespace(string text)
{
// Avoid creating iterator for trivial case
if (text.Length == 0)
{
return true;
}
foreach (char c in text)
{
// Could use Char.IsWhiteSpace(c) instead
if (c==' ' || c=='\t' || c=='\r' || c=='\n')
{
continue;
}
return false;
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
您可能还会考虑您希望该方法执行的text操作null.
可能进一步微观优化以进行试验:
是foreach不是使用较慢的速度或for像下面的一个循环?请注意,使用for循环,您可以if (text.Length==0)在开始时删除" "测试.
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
// ...
Run Code Online (Sandbox Code Playgroud)与上面相同,但挂起Length电话.请注意,这是不利于正常的数组,但可能是字符串有用.我没有测试过.
int length = text.Length;
for (int i = 0; i < length; i++)
{
char c = text[i];
Run Code Online (Sandbox Code Playgroud)在循环体中,我们得到的和之间有什么不同(速度):
if (c != ' ' && c != '\t' && c != '\r' && c != '\n')
{
return false;
}
Run Code Online (Sandbox Code Playgroud)开关/箱子会更快吗?
switch (c)
{
case ' ': case '\r': case '\n': case '\t':
return false;
}
Run Code Online (Sandbox Code Playgroud)修剪行为的更新
我一直在研究如何Trim才能如此高效.似乎Trim只会在需要时创建一个新字符串.如果它可以返回this或""将:
using System;
class Test
{
static void Main()
{
CheckTrim(string.Copy(""));
CheckTrim(" ");
CheckTrim(" x ");
CheckTrim("xx");
}
static void CheckTrim(string text)
{
string trimmed = text.Trim();
Console.WriteLine ("Text: '{0}'", text);
Console.WriteLine ("Trimmed ref == text? {0}",
object.ReferenceEquals(text, trimmed));
Console.WriteLine ("Trimmed ref == \"\"? {0}",
object.ReferenceEquals("", trimmed));
Console.WriteLine();
}
}
Run Code Online (Sandbox Code Playgroud)
这意味着这个问题中的任何基准都应该使用混合数据,这一点非常重要:
当然,这四者之间的"现实世界"平衡是无法预测的......
基准
我已经对我的原始建议进行了一些基准测试,并且我的投入似乎在我投入的所有内容中获胜,这让我感到惊讶,因为其他答案的结果.但是,我还基准之间的差异foreach,for使用text.Length,for使用text.Length一次,然后扭转了迭代顺序,并for以悬挂的长度.
基本上for循环非常快,但提升长度检查使其慢于foreach.反转for循环方向也略慢foreach.我强烈怀疑JIT在这里做了一些有趣的事情,包括删除重复的边界检查等.
using System;
using BenchmarkHelper;
public class TrimStrings
{
static void Main()
{
Test("");
Test(" ");
Test(" x ");
Test("x");
Test(new string('x', 1000));
Test(" " + new string('x', 1000) + " ");
Test(new string(' ', 1000));
}
static void Test(string text)
{
bool expectedResult = text.Trim().Length == 0;
string title = string.Format("Length={0}, result={1}", text.Length,
expectedResult);
var results = TestSuite.Create(title, text, expectedResult)
/* .Add(x => x.Trim().Length == 0, "Trim().Length == 0")
.Add(x => x.Trim() == "", "Trim() == \"\"")
.Add(x => x.Trim().Equals(""), "Trim().Equals(\"\")")
.Add(x => x.Trim() == string.Empty, "Trim() == string.Empty")
.Add(x => x.Trim().Equals(string.Empty), "Trim().Equals(string.Empty)")
*/
.Add(OriginalIsEmptyOrWhitespace)
.Add(IsEmptyOrWhitespaceForLoop)
.Add(IsEmptyOrWhitespaceForLoopReversed)
.Add(IsEmptyOrWhitespaceForLoopHoistedLength)
.RunTests()
.ScaleByBest(ScalingMode.VaryDuration);
results.Display(ResultColumns.NameAndDuration | ResultColumns.Score,
results.FindBest());
}
public static bool OriginalIsEmptyOrWhitespace(string text)
{
if (text.Length == 0)
{
return true;
}
foreach (char c in text)
{
if (c==' ' || c=='\t' || c=='\r' || c=='\n')
{
continue;
}
return false;
}
return true;
}
public static bool IsEmptyOrWhitespaceForLoop(string text)
{
for (int i=0; i < text.Length; i++)
{
char c = text[i];
if (c==' ' || c=='\t' || c=='\r' || c=='\n')
{
continue;
}
return false;
}
return true;
}
public static bool IsEmptyOrWhitespaceForLoopReversed(string text)
{
for (int i=text.Length-1; i >= 0; i--)
{
char c = text[i];
if (c==' ' || c=='\t' || c=='\r' || c=='\n')
{
continue;
}
return false;
}
return true;
}
public static bool IsEmptyOrWhitespaceForLoopHoistedLength(string text)
{
int length = text.Length;
for (int i=0; i < length; i++)
{
char c = text[i];
if (c==' ' || c=='\t' || c=='\r' || c=='\n')
{
continue;
}
return false;
}
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
============ Length=0, result=True ============
OriginalIsEmptyOrWhitespace 30.012 1.00
IsEmptyOrWhitespaceForLoop 30.802 1.03
IsEmptyOrWhitespaceForLoopReversed 32.944 1.10
IsEmptyOrWhitespaceForLoopHoistedLength 35.113 1.17
============ Length=1, result=True ============
OriginalIsEmptyOrWhitespace 31.150 1.04
IsEmptyOrWhitespaceForLoop 30.051 1.00
IsEmptyOrWhitespaceForLoopReversed 31.602 1.05
IsEmptyOrWhitespaceForLoopHoistedLength 33.383 1.11
============ Length=3, result=False ============
OriginalIsEmptyOrWhitespace 30.221 1.00
IsEmptyOrWhitespaceForLoop 30.131 1.00
IsEmptyOrWhitespaceForLoopReversed 34.502 1.15
IsEmptyOrWhitespaceForLoopHoistedLength 35.690 1.18
============ Length=1, result=False ============
OriginalIsEmptyOrWhitespace 31.626 1.05
IsEmptyOrWhitespaceForLoop 30.005 1.00
IsEmptyOrWhitespaceForLoopReversed 32.383 1.08
IsEmptyOrWhitespaceForLoopHoistedLength 33.666 1.12
============ Length=1000, result=False ============
OriginalIsEmptyOrWhitespace 30.177 1.00
IsEmptyOrWhitespaceForLoop 33.207 1.10
IsEmptyOrWhitespaceForLoopReversed 30.867 1.02
IsEmptyOrWhitespaceForLoopHoistedLength 31.837 1.06
============ Length=1002, result=False ============
OriginalIsEmptyOrWhitespace 30.217 1.01
IsEmptyOrWhitespaceForLoop 30.026 1.00
IsEmptyOrWhitespaceForLoopReversed 34.162 1.14
IsEmptyOrWhitespaceForLoopHoistedLength 34.860 1.16
============ Length=1000, result=True ============
OriginalIsEmptyOrWhitespace 30.303 1.01
IsEmptyOrWhitespaceForLoop 30.018 1.00
IsEmptyOrWhitespaceForLoopReversed 35.475 1.18
IsEmptyOrWhitespaceForLoopHoistedLength 40.927 1.36
Run Code Online (Sandbox Code Playgroud)