Сравнение производительности операций подстроки между .NET и Java - PullRequest
9 голосов
/ 13 августа 2010

Получение подстрок строки - очень распространенная операция по обработке строк, но я слышал, что могут быть значительные различия в производительности / реализации между платформой Java и .NET. В частности, я слышал, что в Java java.lang.String предлагает постоянную операцию времени для substring, но в .NET, System.String предлагает линейную производительность Substring.

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

Ответы [ 4 ]

11 голосов
/ 13 августа 2010

В .NET Substring - это O (n), а не O (1) в Java. Это связано с тем, что в .NET объект String сам содержит все фактические символьные данные 1 , поэтому взятие подстроки предполагает копирование всех данных в новой подстроке. В Java substring может просто создать новый объект, ссылающийся на исходный массив символов, с другим начальным индексом и длиной.

Есть плюсы и минусы каждого подхода:

  • . Подход .NET имеет лучшую когерентность кэша, создает меньше объектов 2 и избегает ситуации, когда одна маленькая подстрока предотвращает сбор очень большого char[] мусора. Я верю, что в некоторых случаях это может сделать взаимодействие очень легким, внутренне.
  • Подход Java делает подстроку очень эффективной, и, возможно, некоторые другие операции тоже

В моей статье strings .

есть немного больше деталей.

Что касается общего вопроса о том, как избежать ошибок в производительности, я думаю, у меня должен быть готовый ответ, готовый вырезать и вставлять: убедитесь, что ваша архитектура эффективна, и реализуйте ее наиболее читабельным способом , Измеряйте производительность и оптимизируйте места, где вы найдете узкие места.


1 Кстати, это делает string очень особенным - это единственный тип, не относящийся к массиву, объем памяти которого зависит от экземпляра в пределах одного и того же CLR.

2 Для маленьких струн это большая победа. Достаточно плохо, что есть все издержки одного объекта, но если задействован также дополнительный массив, односимвольная строка может занимать около 36 байт в Java. (Это число «палец в воздухе» - я не могу вспомнить точные накладные расходы на объект. Это также будет зависеть от используемой виртуальной машины.)

2 голосов
/ 13 августа 2010

Использование отражателя это то, что вы получаете от Substring (Int32, Int32)

[SecuritySafeCritical, TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public string Substring(int startIndex, int length)
{
    return this.InternalSubStringWithChecks(startIndex, length, false);
}

если вы продолжаете входить внутри, последний вызов -

internal static unsafe void wstrcpy(char* dmem, char* smem, int charCount)

, который копирует символы с помощью указателей. Полный код на самом деле выглядит большим, но вы не увидите, насколько он быстрым или медленным, пока не запустите его и не сравните его.

1 голос
/ 13 августа 2010

В соответствии с этим не совсем: C # Подстрока

0 голосов
/ 13 августа 2010

Это действительно зависит от вашей рабочей нагрузки.Если вы зацикливаетесь и выполняете много вызовов подстрок, у вас могут возникнуть проблемы.Для поста SO, на который вы ссылаетесь, я сомневаюсь, что это когда-нибудь станет проблемойОднако при таком подходе вы всегда можете оказаться в ситуации «смерти от тысячи порезов».В сообщении SO, на которое вы ссылаетесь, у нас есть следующее:

String after = before.Substring(0, 1).ToUpper() + before.Substring(1);

Предполагая, что компилятор не выполняет сумасшедших оптимизаций, это создаст как минимум четыре новые строки (2 Substring вызовы, a ToUpper вызов и конкатенация).Подстрока реализована точно так, как вы ожидаете (копирование строки), но три из этих строк, выделенных выше, быстро станут мусором.Многое из этого создаст ненужную нагрузку на память.Я говорю «ненужный», потому что вы, вероятно, можете придумать более экономичное решение, потратив немного больше времени.

В конце концов, профилировщик - ваш лучший друг:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...