Самый эффективный способ определить, если длина строки! = 0?

Я пытаюсь ускорить следующее:

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

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

Проблема, кажется, что.Length на самом деле считает символы в строке, и это - путь больше работы, чем мне нужно. У кого-либо есть идея о том, как ускорить это?

Или, есть ли способ определить, существует ли s [0], w/out проверка остальной части строки?

10
задан Anthony Pegram 2 August 2010 в 17:27
поделиться

8 ответов

Доступ к свойству 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;
}
5
ответ дан 3 December 2019 в 13:43
поделиться

Вот функция String.IsNullOrEmpty -

if (!String.IsNullOrEmpty(yourstring))
{
  // your code
}
3
ответ дан 3 December 2019 в 13:43
поделиться

Основываясь на намерениях, описанных в вашем ответе, почему бы вам просто не попробовать использовать эту встроенную опцию на Split:

s.Split(new[]{" "}, StringSplitOptions.RemoveEmptyEntries);
1
ответ дан 3 December 2019 в 13:43
поделиться

String.IsNullOrEmpty - предпочтительный метод проверки строк нулевой или нулевой длины.

Внутри будет использоваться длина. Однако свойство Length для строки не следует вычислять "на лету".

Если вы абсолютно уверены, что строка никогда не будет нулевой и у вас есть серьезные возражения против String.IsNullOrEmpty, то наиболее эффективным кодом, который я могу придумать, будет:

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

Или, возможно, даже лучше:

if(s != "")
{
    // Do Something
}
9
ответ дан 3 December 2019 в 13:43
поделиться

Как всегда с performace: benchmark.
yourString.Length против String.IsNullOrEmpty(yourString)

Используя C# 3.5 или ранее, вы захотите проверить yourString.Length против String.IsNullOrEmpty(yourString)

Используя C# 4, сделайте оба вышеприведенных варианта и добавьте String. IsNullOrWhiteSpace(yourString)

Конечно, если вы знаете, что ваша строка никогда не будет пустой, вы можете просто попытаться получить доступ к s[0] и обработать исключение, когда его там нет. Это не обычно хорошая практика, но это может быть ближе к тому, что вам нужно (если s всегда должно иметь непустое значение).

0
ответ дан 3 December 2019 в 13:43
поделиться
        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

после исправления кода

0
ответ дан 3 December 2019 в 13:43
поделиться

РЕДАКТИРОВАТЬ: Теперь, когда вы предоставили дополнительный контекст:

  • Пытаясь воспроизвести это, мне вообще не удалось найти узкое место в string.Length . Единственный способ сделать это быстрее - закомментировать как тест , так и тело блока if , что на самом деле нечестно. Простое комментирование условия замедляло работу, т.е. безоговорочное копирование ссылки было медленнее, чем проверка условия.

  • Как уже указывалось, использование перегрузки string.Split , которая удаляет пустые записи, является для вас настоящей убийственной оптимизацией.

  • Вы можете пойти дальше, избегая создания нового массива символов с пробелом каждый раз. Вы всегда будете эффективно передавать одно и то же, так почему бы не воспользоваться этим?

  • Пустые массивы фактически неизменяемы. Вы можете оптимизировать регистр 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)

- лучший способ пойти, если вы ищете чистую производительность IMO. Лично в большинстве случаев я бы написал:

if (s != "")

, чтобы было понятнее, что нас не столько интересует длина, сколько значение, как то, является ли это пустой строкой. Это будет немного медленнее, чем тест на длину, но я считаю, что это яснее. Как всегда, я бы выбрал самый ясный код, пока у вас не будут данные теста / профилирования, чтобы указать, что это действительно является узким местом. Я знаю, что ваш вопрос явно касается поиска наиболее эффективного теста, но я подумал, что все равно упомяну об этом. Есть ли у вас доказательства того, что этот является узким местом?

РЕДАКТИРОВАТЬ: Просто чтобы более четко обосновать мое предложение , а не с использованием string.IsNullOrEmpty : вызов к этому методу подсказывает мне, что вызывающий объект явно пытается справиться со случаем, когда переменная равна нулю, иначе они бы не упомянули об этом.Если на этом этапе кода это считается ошибкой, если переменная имеет значение null, то вам не следует пытаться обработать это как нормальный случай.

В этой ситуации проверка Length на самом деле лучше в одном смысле, чем тест на неравенство, который я предложил: она действует как неявное утверждение, что переменная не равна нулю. . Если у вас есть ошибка, и значение равно null, тест вызовет исключение, и ошибка будет обнаружена раньше. Если вы используете тест на равенство, он будет рассматривать null как отличное от пустой строки, поэтому он попадет в тело вашего оператора «if». Если вы используете string.IsNullOrEmpty , он будет рассматривать null как то же самое, что и пустой, поэтому он не попадет в блок.

23
ответ дан 3 December 2019 в 13:43
поделиться

Просто используйте String.Split (new char [] {''}, StringSplitOptions.RemoveEmptyEntries) , и он все сделает за вас.

0
ответ дан 3 December 2019 в 13:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: