确定字符串长度是否!= 0的最有效方法?

发布于 2024-09-13 05:30:27 字数 230 浏览 3 评论 0原文

我正在尝试加快以下速度:

string s; //--> s is never null

if (s.Length != 0)
{
   <do something>
}

问题是,.Length 实际上计算了字符串中的字符,这比我需要的工作量要多。有人知道如何加快速度吗?

或者,有没有办法确定 s[0] 是否存在,而不检查字符串的其余部分?

I'm trying to speed up the following:

string s; //--> s is never null

if (s.Length != 0)
{
   <do something>
}

Problem is, it appears the .Length actually counts the characters in the string, and this is way more work than I need. Anybody have an idea on how to speed this up?

Or, is there a way to determine if s[0] exists, w/out checking the rest of the string?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

韵柒 2024-09-20 05:30:27

编辑:现在您已经提供了更多上下文:

  • 尝试重现此内容,我根本无法在 string.Length 中找到瓶颈。使其更快的唯一方法是注释掉测试和 if 块的主体 - 这并不公平。只是注释掉条件会减慢速度,即无条件复制引用比检查条件慢。

  • 正如已经指出的那样,使用 string.Split 的重载来删除空条目是真正的杀手级优化。

  • 您可以更进一步,避免每次都创建一个只有空格的新字符数组。您总是会有效地传递相同的内容,那么为什么不利用这一点呢?

  • 空数组实际上是不可变的。您可以通过始终返回相同的内容来优化 null/空情况。

优化后的代码变为:

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)

t null,那么如果您正在寻找原始性能(IMO), 是最好的方法。就我个人而言,在大多数情况下,我会写:

if (s != "")

为了更清楚地表明,我们对长度作为值不太感兴趣,而对这是否是空字符串更感兴趣。这会比长度测试稍微慢一些,但我相信它更清晰。一如既往,我会选择最清晰的代码,直到您拥有基准/分析数据来表明这确实是一个瓶颈。我知道您的问题明确是关于寻找最有效的测试,但我想无论如何我都会提到这一点。您有证据表明这是一个瓶颈吗?

编辑:只是为了更清楚地说明我建议使用string.IsNullOrEmpty:对该方法的调用表明调用者正在明确尝试处理这种情况其中变量为 null,否则他们不会提及它。如果在代码的这一点上,如果变量 null,那么您不应该尝试将其作为正常情况处理。

在这种情况下,Length 检查实际上在某种程度上比我建议的不等式测试更好:它充当变量不为空的隐式断言。如果您有错误并且该错误 null,则测试将抛出异常,并且该错误将被尽早检测到。如果您使用相等测试,它会将 null 视为与空字符串不同,因此它将进入“if”语句的主体。如果您使用 string.IsNullOrEmpty ,它将把 null 视为与空相同,因此它不会进入该块。

EDIT: Now that you've provided some more context:

  • Trying to reproduce this, I failed to find a bottleneck in string.Length at all. The only way of making it faster was to comment out both the test and the body of the if block - which isn't really fair. Just commenting out the condition slowed things down, i.e. unconditionally copying the reference was slower than checking the condition.

  • As has been pointed out, using the overload of string.Split which removes empty entries for you is the real killer optimization.

  • You can go further, by avoiding creating a new char array with just a space in every time. You're always going to pass the same thing effectively, so why not take advantage of that?

  • Empty arrays are effectively immutable. You can optimize the null/empty case by always returning the same thing.

The optimized code becomes:

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 absolutely does not count the letters in the string. The value is stored as a field - although I seem to remember that the top bit of that field is used to remember whether or not all characters are ASCII (or used to be, anyway) to enable other optimisations. So the property access may need to do a bitmask, but it'll still be O(1) and I'd expect the JIT to inline it, too. (It's implemented as an extern, but hopefully that wouldn't affect the JIT in this case - I suspect it's a common enough operation to potentially have special support.)

If you already know that the string isn't null, then your existing test of

if (s.Length != 0)

is the best way to go if you're looking for raw performance IMO. Personally in most cases I'd write:

if (s != "")

to make it clearer that we're not so much interested in the length as a value as whether or not this is the empty string. That will be slightly slower than the length test, but I believe it's clearer. As ever, I'd go for the clearest code until you have benchmark/profiling data to indicate that this really is a bottleneck. I know your question is explicitly about finding the most efficient test, but I thought I'd mention this anyway. Do you have evidence that this is a bottleneck?

EDIT: Just to give clearer reasons for my suggestion of not using string.IsNullOrEmpty: a call to that method suggests to me that the caller is explicitly trying to deal with the case where the variable is null, otherwise they wouldn't have mentioned it. If at this point of the code it counts as a bug if the variable is null, then you shouldn't be trying to handle it as a normal case.

In this situation, the Length check is actually better in one way than the inequality test I've suggested: it acts as an implicit assertion that the variable isn't null. If you have a bug and it is null, the test will throw an exception and the bug will be detected early. If you use the equality test it will treat null as being different to the empty string, so it will go into your "if" statement's body. If you use string.IsNullOrEmpty it will treat null as being the same as empty, so it won't go into the block.

时光清浅 2024-09-20 05:30:27

String.IsNullOrEmpty 是检查 null 或零长度字符串的首选方法。

在内部,它将使用长度。不过,不应即时计算字符串的 Length 属性。

如果您绝对确定该字符串永远不会为空,并且您强烈反对 String.IsNullOrEmpty,那么我能想到的最有效的代码是:

if(s.Length > 0)
{
    // Do Something
}

或者,可能更好:

if(s != "")
{
    // Do Something
}

String.IsNullOrEmpty is the preferred method for checking for null or zero length strings.

Internally, it will use Length. The Length property for a string should not be calculated on the fly though.

If you're absolutely certain that the string will never be null and you have some strong objection to String.IsNullOrEmpty, the most efficient code I can think of would be:

if(s.Length > 0)
{
    // Do Something
}

Or, possibly even better:

if(s != "")
{
    // Do Something
}
快乐很简单 2024-09-20 05:30:27

访问 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;
}

Accessing the Length property shouldn't do a count -- .NET strings store a count inside the object.

The SSCLI/Rotor source code contains an interesting comment which suggests that String.Length is (a) efficient and (b) magic:

// 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;
}
花期渐远 2024-09-20 05:30:27

这是函数 String.IsNullOrEmpty -

if (!String.IsNullOrEmpty(yourstring))
{
  // your code
}

Here is the function String.IsNullOrEmpty -

if (!String.IsNullOrEmpty(yourstring))
{
  // your code
}
终遇你 2024-09-20 05:30:27
String.IsNullOrWhiteSpace(s);

如果 s 为 null 或空,或者 s 仅由空白字符组成,则为 true。

String.IsNullOrWhiteSpace(s);

true if s is null or Empty, or if s consists exclusively of white-space characters.

夜巴黎 2024-09-20 05:30:27

与往常一样,性能:基准。
使用 C# 3.5 或之前版本,您需要

使用 C# 4 测试 yourString.LengthString.IsNullOrEmpty(yourString),执行上述两项操作并添加 String.IsNullOrWhiteSpace(yourString)

当然,如果您知道字符串永远不会为空,您可以尝试访问 s[0] 并在异常不存在时处理异常。这通常不是一个好的做法,但它可能更接近您的需要(如果 s 应该始终具有非空值)。

As always with performace: benchmark.
Using C# 3.5 or before, you'll want to test yourString.Length vs String.IsNullOrEmpty(yourString)

using C# 4, do both of the above and add String.IsNullOrWhiteSpace(yourString)

Of course, if you know your string will never be empty, you could just attempt to access s[0] and handle the exception when it's not there. That's not normally good practice, but it may be closer to what you need (if s should always have a non-blank value).

来世叙缘 2024-09-20 05:30:27
        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 少

在修复代码后,

        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));
        }

Using the stopwatch the s.length != 0 takes less ticks then s == String.Empty

after I fix the code

凉月流沐 2024-09-20 05:30:27

根据您在答案中描述的意图,为什么不尝试在 Split 上使用此内置选项:

s.Split(new[]{" "}, StringSplitOptions.RemoveEmptyEntries);

Based on your intent described in your answer, why don't you just try using this built-in option on Split:

s.Split(new[]{" "}, StringSplitOptions.RemoveEmptyEntries);
永不分离 2024-09-20 05:30:27

只需使用 String.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries) 即可,它会为您完成这一切。

Just use String.Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries) and it will do it all for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文