2016-08-31 2 views
0

У меня есть код, который в значительной степени опирается на метод String.Substring, до того момента, когда метод Substring замедляет мое приложение. Я знаю, что диапазон, который я хочу получить, находится внутри String (это не выходит за рамки.) Может ли что-то, что я мог бы использовать вместо подстроки, было бы быстрее? Могу ли я написать собственный метод подстроки, который может отказаться от любых проверок границ?Заменить C# String.Substring

Пример кода:

public String get_element(int element_number) { 
     int count = 0; 
     int start_index = 0; 
     int end_index = 0; 
     int current_index = 0; 

     while (count < element_number && current_index != -1) { 
      current_index = line_text.IndexOf(x12_reader.element_delimiter, start_index); 
      start_index = current_index + 1; 
      count++; 
     } 

     if (current_index != -1) { 
      end_index = line_text.IndexOf(x12_reader.element_delimiter, start_index); 
      if (end_index == -1) end_index = line_text.Length; 
      return line_text.Substring(start_index, end_index - start_index); ; 
     } else { 
      return ""; 
     } 
    } 

Я вижу много комментариев с просьбой, если подстрока действительно проблема. Я знаю, что проблема заключается в подстроке. Я выполняю профилирование в Visual Studio, и он указал на подстроку в качестве виновника. Также я не могу назвать эту функцию меньше, чем сейчас. Единственное место, которое я оставил для оптимизации, - это функция подстроки. Я знаю, что это так.

+6

Как вы определили, что 'Подстрока' - это горло бутылки? – juharr

+1

Можете ли вы позволить хранить ваши данные в виде массива вместо строкового DSV. Например, можете ли вы начать разбить 'line_text' на массив и просто получить доступ к элементу' element_number'? – Yakuza

+3

Я был бы удивлен тем, что проверка границ является виновником вашей проблемы с производительностью. – hatchet

ответ

1

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

Следующий вопрос: что именно вы делаете с результатом? Возможно, вы могли бы изменить подпись метода get_element, например. для получения StringBuilder, а затем для копирования символов из целевой строки вместо создания новой строки.

public void get_element(int element_number, StringBuilder buffer) 
{ 
    ... 
    // instead of: return line_text.Substring(...); 
    buffer.Append(line_text, start_index, end_index - start_index); 
} 

В любом случае стоимость строительства новых строк не слишком велика. Возможно, есть и другие причины, по которым производительность плохо в вашем случае. Может быть, вы делаете слишком много конкатенаций строк, возвращаемых этим методом?

+0

Вместо этого я попытался использовать stringbuilder, и производительность медленнее. Я называю этот метод миллионы раз. – Daniel

+0

'StringBuilder' приведет к повышению производительности * только *, если он используется много раз во многих вызовах' get_element'. Можете ли вы добавить еще один код в вопрос? В частности, я хотел бы видеть, что вы делаете в конце вызова, то есть что происходит со строкой после ее возврата из метода get_element. –

+0

Возвращенная строка просто сохраняется в большинстве случаев. Будет использоваться позже. Накладные расходы Stringbuilder слишком много, учитывая размер возвращаемых строк. – Daniel

-2

Строка - это только массив символов. Вы можете пройти через массив символов между вашими известными границами и заменить символ.

+0

Это совсем не так. Строка - это объект, это не массив символов. Кроме того, строка является * неизменным * объектом, что означает, что вы не можете ее модифицировать, не создавая новый объект. – dman2306

+0

@ dman2306 Ответ Рика на строку, являющуюся только массивом символов, является правильным. Внутренне это небезопасный класс, который использует CLR для хранения массива char *. Вы можете выполнить 'tring test =" test "; \t \t небезопасного { \t \t фиксированный (символ * р = тест) \t \t { \t \t \t р [0] = 'С'; \t \t} \t} 'и это совершенно законно, и он не восстанавливает строку, а просто использует небезопасные. – Dispersia

+0

Вы можете изменить строку из небезопасного кода, но ... это большой нет-нет в .NET, потому что все вокруг строкового объекта предполагает, что он не изменится. Во всяком случае, речь идет о другом: здесь часть строки должна быть перенесена в другое место, а не изменена. –

1

Я сомневаюсь, что проблема вызвана проверкой границ внутри метода Substring.

Но если вы хотите быть уверены, и небезопасный код разрешен, вы можете попробовать следующий string конструктор:

public unsafe String(
    char* value, 
    int startIndex, 
    int length 
) 

так:

public static class StringUtils 
{ 
    public static unsafe string UnsafeSubstring(this string source, int startIndex, int length) 
    { 
     fixed (char* chars = source) 
      return new string(chars, startIndex, length); 
    } 
} 

Затем заменить Substring звонки с UnsafeSubstring и посмотреть если есть какая-либо заметная разница.

+0

это (почти) идентично нормальной подстроке без вызовов безопасности. – Dispersia

+2

@Dispersia Правильно. Как я уже упоминал в начале, я сомневаюсь, что проблема вызвана вызовами безопасности. Таким образом, вышесказанное - это просто ответить OP "* Могу ли я написать свой собственный метод подстроки, который мог бы отказаться от любых проверок границ? *" –

Смежные вопросы