我正在尝试加速以下过程:
string s; //--> s is never null
if (s.Length != 0)
{
<do something>
}
问题是,似乎.Length实际上计算的是字符串中的字符数,这比我需要的工作要多得多。有没有人有加速的想法?
或者,有没有办法确定s [0]是否存在,而不必检查字符串的其余部分?
我正在尝试加速以下过程:
string s; //--> s is never null
if (s.Length != 0)
{
<do something>
}
问题是,似乎.Length实际上计算的是字符串中的字符数,这比我需要的工作要多得多。有没有人有加速的想法?
或者,有没有办法确定s [0]是否存在,而不必检查字符串的其余部分?
编辑: 现在你提供了更多背景:
尝试复现这个问题时,我并没有发现 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 - 我认为这是一个足够常见的操作,有可能得到特殊支持。)如果您已经知道字符串不为空,则您现有的测试可以简化为:if (s.Length != 0)
在我看来,如果你追求原始性能,使用这种方式是最佳选择。在大多数情况下,我会这样编写:
if (s != "")
为了使其更清晰,我们关心的并不是字符串长度作为一个值,而是它是否为空字符串。这个测试比长度测试稍微慢一些,但我认为它更加清晰。像往常一样,在您拥有基准/分析数据表明这确实是一个瓶颈之前,我会选择最清晰的代码。我知道您的问题明确是要找到最有效的测试方法,但我想无论如何都要提一下。您有证据表明这是一个瓶颈吗?
编辑:只是为了更清楚地说明我建议不要使用string.IsNullOrEmpty
的原因:调用该方法表明调用方明确地试图处理变量为null的情况,否则他们不会提到它。如果在代码的这个阶段,如果变量为null就算作一个bug的话,那么你不应该将其视为正常情况来处理。
在这种情况下,Length
检查实际上比我提出的不等式测试方式在某些方面更好:它扮演了一个隐式的断言,即变量不为null。如果您有一个bug,并且它是null,则该测试将引发异常并及早检测到错误。如果您使用相等性测试,则会将null视为与空字符串不同,因此它将进入“if”语句的主体。如果您使用string.IsNullOrEmpty
,则会将null视为与空相同,因此不会进入该块。
unsafe void PeekLength(String s)
{
fixed (char* st = s)
{
try
{
int* l = (int*)(st - 2);
Console.WriteLine("Length is " + *l);
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
}
- Sergey.quixoticaxis.IvanovString.IsNullOrEmpty是检查null或空字符串的首选方法。
在内部,它将使用Length属性。但是应该避免实时计算字符串的长度。
如果您绝对确定该字符串永远不会为空,并且您对String.IsNullOrEmpty有一些强烈的反感,那么我能想到的最有效的代码是:
if(s.Length > 0)
{
// Do Something
}
或者,可能更好的是:
if(s != "")
{
// Do Something
}
String.Empty
进行比较。 - ankitjaininfostring.Length == 0
是确定字符串是否为空的最快方法。 - Matt Greer访问Length
属性不应该进行计数——.NET字符串在对象内部存储计数。
SSCLI/Rotor源代码包含了一个有趣的注释,它表明String.Length
既有效率又神奇:
// 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
}
String.IsNullOrWhiteSpace(s);
如果 s 为 null 或空,或者 s 仅由空格字符组成,则为 true。
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));
}
根据您在答案中描述的意图,为什么不尝试使用此Split内置选项:
s.Split(new[]{" "}, StringSplitOptions.RemoveEmptyEntries);
关于性能,一如既往的要进行基准测试。
使用C# 3.5或更早版本,您将想要测试yourString.Length
与String.IsNullOrEmpty(yourString)
之间的差异。
使用C# 4,执行上述两个操作并添加String.IsNullOrWhiteSpace(yourString)
当然,如果您知道您的字符串永远不会为空,您可以尝试访问s[0]
并在不存在时处理异常。这通常不是一个好习惯,但它可能更接近您所需的内容(如果s应始终具有非空值)。
String.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries)
,它就可以为您完成所有操作。