Когда я выполнял простое измерение производительности, я был поражен, увидев, что вызов String.IndexOf(char)
был на самом деле медленнее, чем делать это вручную! Это правда? Вот мой тестовый код:
const string str = @"91023m lkajsdfl;jkasdf;piou-09324\\adf \asdf\45\ 65u\ 86\ 8\\\;";
static int testIndexOf() { return str.IndexOf('\\'); }
static int testManualIndexOf() {
string s = str;
for (int i = 0; i < s.Length; ++i)
if (s[i] == '\\') return i;
return -1;
}
Я запускал каждый метод 25 миллионов раз и измерял время, используя Stopwatch
. Ручная версия была на 25% быстрее, чем другая.
Есть мысли?!
Редактировать 2: Запуск тестов на другом компьютере с .NET 4.0 дает результаты, очень похожие на те, что были в ответе Марка Гравелла. String.IndexOf(char)
быстрее , чем ручной поиск.
Редактировать: Сегодня (4 января 2009 г.) Я хотел более подробно проверить эту проблему, поэтому создал новый проект и написал код, который вы найдете ниже. Я получил следующие результаты при запуске режима выпуска из cmd для 100 миллионов итераций:
- String. IndexOf : 00:00:07.6490042
- MyString.PublicIndexOf : 00:00:05.6676471
- MyString.InternIndexOf : 00:00:06.1191796
- MyString.PublicIndexOf2: 00:00:09.1363687
- MyString.InternIndexOf2: 00:00:09.1182569
Я проводил эти тесты не менее 20 раз, получая почти одинаковые результаты каждый раз. Моя машина - XP SP3, VS 2008 SP1, P4 3.0 ГГц без гиперпоточности и 1 ГБ оперативной памяти. Я нахожу результаты действительно странными. Как видите, String.IndexOf
был примерно на 33% медленнее, чем мой PublicIndexOf
. Даже более странно, я написал тот же метод, что и internal
, и он был примерно на 8% медленнее, чем public
! Я не понимаю, что происходит, и я надеюсь, что вы могли бы помочь мне понять!
Код тестирования приведен ниже. (Извините за повторный код, но я обнаружил, что использование делегата показывало разные сроки, при этом методы public
и internal
занимали одно и то же время.)
public static class MyString {
public static int PublicIndexOf(string str, char value) {
for (int i = 0; i < str.Length; ++i)
if (str[i] == value) return i;
return -1;
}
internal static int InternIndexOf(string str, char value) {
for (int i = 0; i < str.Length; ++i)
if (str[i] == value) return i;
return -1;
}
public static int PublicIndexOf2(string str, char value, int startIndex) {
if (startIndex < 0 || startIndex >= str.Length)
throw new ArgumentOutOfRangeException("startIndex");
for (; startIndex < str.Length; ++startIndex)
if (str[startIndex] == value) return startIndex;
return -1;
}
internal static int InternIndexOf2(string str, char value, int startIndex) {
if (startIndex < 0 || startIndex >= str.Length)
throw new ArgumentOutOfRangeException("startIndex");
for (; startIndex < str.Length; ++startIndex)
if (str[startIndex] == value) return startIndex;
return -1;
}
}
class Program {
static void Main(string[] args) {
int iterations = 100 * 1000 * 1000; // 100 millions
char separator = '\\';
string str = @"91023m lkajsdfl;jkasdf;piou-09324\\adf \asdf\45\ 65u\ 86\ 8\\\;";
Stopwatch watch = new Stopwatch();
// test String.IndexOf
int sum = 0;
watch.Start();
for (int i = 0; i < iterations; ++i)
sum += str.IndexOf(separator);
watch.Stop();
Console.WriteLine(" String. IndexOf : ({0}, {1})", watch.Elapsed, sum);
// test MyString.PublicIndexOf
sum = 0;
watch.Reset(); watch.Start();
for (int i = 0; i < iterations; ++i)
sum += MyString.PublicIndexOf(str, separator);
watch.Stop();
Console.WriteLine("MyString.PublicIndexOf : ({0}, {1})", watch.Elapsed, sum);
// test MyString.InternIndexOf
sum = 0;
watch.Reset(); watch.Start();
for (int i = 0; i < iterations; ++i)
sum += MyString.InternIndexOf(str, separator);
watch.Stop();
Console.WriteLine("MyString.InternIndexOf : ({0}, {1})", watch.Elapsed, sum);
// test MyString.PublicIndexOf2
sum = 0;
watch.Reset(); watch.Start();
for (int i = 0; i < iterations; ++i)
sum += MyString.PublicIndexOf2(str, separator,0);
watch.Stop();
Console.WriteLine("MyString.PublicIndexOf2: ({0}, {1})", watch.Elapsed, sum);
// test MyString.InternIndexOf2
sum = 0;
watch.Reset(); watch.Start();
for (int i = 0; i < iterations; ++i)
sum += MyString.InternIndexOf2(str, separator,0);
watch.Stop();
Console.WriteLine("MyString.InternIndexOf2: ({0}, {1})", watch.Elapsed, sum);
}
}