[英]Most efficient way to determine if a string length != 0?
我正在努力加快以下方面的步伐:
string s; //--> s is never null
if (s.Length != 0)
{
<do something>
}
问题是,看起来.Length实际上是对字符串中的字符进行计数,这比我需要的工作更多。 有人知道如何加快速度吗?
或者,有没有办法确定s [0]是否存在,w / out检查字符串的其余部分?
编辑:现在您已经提供了更多上下文:
试图重现这一点,我没有找到string.Length
的瓶颈。 使其更快的唯一方法是注释掉if块的测试和正文 - 这不是很公平。 只是注释掉条件会减慢速度,即无条件地复制引用比检查条件要慢。
正如已经指出的那样,使用string.Split
的重载为你删除空条目是真正的杀手优化。
您可以通过避免每次只创建一个空格来创建一个新的char数组。 你总是会有效地传递同样的东西,为什么不利用它呢?
空数组实际上是不可变的。 您可以通过始终返回相同的内容来优化null / empty案例。
优化的代码变为:
private static readonly char[] Delimiters = " ".ToCharArray();
private static readonly string[] EmptyArray = new string[0];
public static string[] SplitOnMultiSpaces(string text)
{
if (string.IsNullOrEmpty(text))
{
return EmptyArray;
}
return text.Split(Delimiters, StringSplitOptions.RemoveEmptyEntries);
}
String.Length
绝对不计算字符串中的字母。 该值存储为一个字段 - 尽管我似乎记得该字段的最高位用于记住所有字符是否都是ASCII(或者过去常常用于启用其他优化)。 所以属性访问可能需要做一个位掩码,但它仍然是O(1)并且我希望JIT也可以内联它。 (它是作为一个extern
实现的,但希望在这种情况下不会影响JIT - 我怀疑这是一个足够普遍的操作,可能有特殊的支持。)
如果您已经知道该字符串不为null,那么您现有的测试
if (s.Length != 0)
如果你正在寻找原始性能IMO,那么这是最好的方法。 我个人在大多数情况下写道:
if (s != "")
更清楚的是,我们对长度的兴趣并不像是否为空字符串。 这将比长度测试略慢,但我相信它更清晰。 与以往一样,我会选择最清晰的代码,直到你有基准/分析数据来表明这确实是一个瓶颈。 我知道你的问题明确是关于找到最有效的测试,但我想我还是会提到这个。 你有证据证明这是一个瓶颈吗?
编辑:只是给我的未使用的建议更明确的理由string.IsNullOrEmpty
:该方法的调用建议,我认为主叫明确设法应付其中变量是空的情况下,否则他们就不会提及它。 如果在代码的这一点上,如果变量为 null则将其视为错误,那么您不应该尝试将其作为正常情况处理。
在这种情况下, Length
检查实际上比我建议的不等式测试更好 :它充当隐式断言,即变量不为空。 如果你有一个bug而且它是 null,那么测试将抛出一个异常,并且会及早发现bug。 如果使用相等性测试,它会将null视为与空字符串不同,因此它将进入“if”语句的主体。 如果使用string.IsNullOrEmpty
它会将null视为与empty相同,因此它不会进入块。
String.IsNullOrEmpty是检查null或零长度字符串的首选方法。
在内部,它将使用长度。 但是,不应该动态计算字符串的Length属性。
如果您完全确定该字符串永远不会为null并且您对String.IsNullOrEmpty有强烈的反对意见,那么我能想到的最有效的代码是:
if(s.Length > 0)
{
// Do Something
}
或者,甚至可能更好:
if(s != "")
{
// Do Something
}
访问Length
属性不应该进行计数 - .NET字符串在对象内部存储计数。
SSCLI / Rotor源代码包含一个有趣的注释,表明String.Length
是(a)有效的和(b)魔术:
// Gets the length of this string
//
/// This is a EE implemented function so that the JIT can recognise is specially
/// and eliminate checks on character fetchs in a loop like:
/// for(int I = 0; I < str.Length; i++) str[i]
/// The actually code generated for this will be one instruction and will be inlined.
//
public extern int Length {
[MethodImplAttribute(MethodImplOptions.InternalCall)]
get;
}
这是函数String.IsNullOrEmpty -
if (!String.IsNullOrEmpty(yourstring))
{
// your code
}
根据您在答案中描述的意图,为什么不尝试在Split上使用此内置选项:
s.Split(new[]{" "}, StringSplitOptions.RemoveEmptyEntries);
String.IsNullOrWhiteSpace(s);
如果s为null或Empty,或者s仅由空格字符组成,则返回true。
与性能一样:基准。
使用C#3.5或之前,您将要测试yourString.Length
vs String.IsNullOrEmpty(yourString)
使用C#4,执行上述两个操作并添加String.IsNullOrWhiteSpace(yourString)
当然,如果你知道你的字符串永远不会是空的,你可以尝试访问s[0]
并在不存在时处理异常。 这通常不是好的做法,但它可能更接近你需要的(如果s应该总是有一个非空白值)。
for (int i = 0; i < 100; i++)
{
System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
string s = "dsfasdfsdafasd";
timer.Start();
if (s.Length > 0)
{
}
timer.Stop();
System.Diagnostics.Debug.Write(String.Format("s.Length != 0 {0} ticks ", timer.ElapsedTicks));
timer.Reset();
timer.Start();
if (s == String.Empty)
{
}
timer.Stop();
System.Diagnostics.Debug.WriteLine(String.Format("s== String.Empty {0} ticks", timer.ElapsedTicks));
}
使用秒表,s.length!= 0需要更少的刻度,然后s == String.Empty
在我修复代码之后
只需使用String.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries)
,它将为您完成所有操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.