Comments 35
Следующий шаг — пересмотр всех топиков в кодобреде :)
Спасибо за интересную статью, но все-же: Хабракат.
Было бы интересно ещё в этом же тесте увидеть график для try-catch валидации…
Я так думаю, что у этого топика будет часть 2.
покопался в исходниках. думаю на больших строках примерно одинаково, потому что внутри оба метода (TryParse и Parse) в итоге юзают один и тот же метод Number.ParseNumber, который и делает всю работу.
вообще есть у кодобреда такое свойство… иногда под ним скрывается очень даж неплохое решение конкретной задачи.
но всё-таки лучше не писать
но всё-таки лучше не писать
int j = i++ + ++i;
* This source code was highlighted with Source Code Highlighter.
В оригинальном коде:
Я подозреваю, что на обработке «ошибки» есть выход из цикла. И тогда код теста производительности должен выглядеть примерно так:
Потому что при пойманной не-цифре проверять дальше смыслу нет. Или я что-то не понял?
- for (int i=0; i<this.textbox1.text.length; i++)
- {
- if (char.IsDigit(this.textbox1.text[i])==false)
- // give any error
- }
* This source code was highlighted with Source Code Highlighter.
Я подозреваю, что на обработке «ошибки» есть выход из цикла. И тогда код теста производительности должен выглядеть примерно так:
- public bool TestIndusCode()
- {
- bool result = true;
- foreach (String str in _generatedDigits)
- {
- for (int i = 0; i < str.Length; i++)
- if (char.IsDigit(str[i]) == false)
- {
- result = false;
- break; //(sic!)
- }
- }
- return (result);
- }
* This source code was highlighted with Source Code Highlighter.
Потому что при пойманной не-цифре проверять дальше смыслу нет. Или я что-то не понял?
Вы правильно поняли. Только если обратите внимание, то в тесте генерируются строки содержащие «правильные» числа.
Вы это совершенно верно подметили. Я тоже первым делом хотел указать, что нужен выход из цикла при срабатывании.
Для этих тестовых данных не изменит картины, а вот на реальных данных ухудшило бы производительность IndusCode() однозначно (и, существенно).
Для этих тестовых данных не изменит картины, а вот на реальных данных ухудшило бы производительность IndusCode() однозначно (и, существенно).
Сейчас немного подправляю код и посмотрю, насколько вставка break'a улучшит результаты при наличии «неправильных чиселок».
Он улучшит код ровно на столько на сколько вы ему подадите плохих данных.
Т.е. результат недвусмысленно связан со статистическими характеристиками исходных данных.
Вы же будете исходные данные создавать? Вот какие константы скормить Рендому() — то и получится. Я имею в виду не его инициализацию большим числом, чтобы числа получись как-бы случайные. Я имею в виду характеристики распределения (дисперсия, мат ожидание, закон...)
(И, да, равномерное распределение можно преобразовать в любое другое).
Т.е. результат недвусмысленно связан со статистическими характеристиками исходных данных.
Вы же будете исходные данные создавать? Вот какие константы скормить Рендому() — то и получится. Я имею в виду не его инициализацию большим числом, чтобы числа получись как-бы случайные. Я имею в виду характеристики распределения (дисперсия, мат ожидание, закон...)
(И, да, равномерное распределение можно преобразовать в любое другое).
Вставьте в IndusCode() выход из цикла и производительность не ухудшится.
foreach (String str in _generatedDigits)
{
for (int i = 0; i < str.Length; i++)
if (char.IsDigit(str[i]))
{
result = false;
}
else
{
return true;//незачем дальше перебирать буковки
}
}
Гм. А почему бы не пользовать:
for (i = 0; i < str.Length; i++)
{
if ((str[i] <'0') | (str[i] > '9')) return false;
}
return true;
for (i = 0; i < str.Length; i++)
{
if ((str[i] <'0') | (str[i] > '9')) return false;
}
return true;
За основу был взят способ предложенный индусом, о котором я писал в предыдущем посте.
1) ||
2) Если присмотреться, можно увидеть, что метод IsDigit делает для ASCII-символов почти то же, что и у вас. А учитывая, что CLR умеет инлайнить простые методы при JIT-компиляции, выигрыш от вашего подхода будет несущественным.
2) Если присмотреться, можно увидеть, что метод IsDigit делает для ASCII-символов почти то же, что и у вас. А учитывая, что CLR умеет инлайнить простые методы при JIT-компиляции, выигрыш от вашего подхода будет несущественным.
1) ага, спасибо, пропустил.
2) IsDigit делает почти тоже, но не только тоже:
IL_0000: ldarg.0
IL_0001: call bool System.Char::IsLatin1(char)
IL_0006: brfalse.s IL_0018
IL_0008: ldarg.0
IL_0009: ldc.i4.s 48
IL_000b: blt.s IL_0016
IL_000d: ldarg.0
IL_000e: ldc.i4.s 57
IL_0010: cgt
IL_0012: ldc.i4.0
IL_0013: ceq
IL_0015: ret
IL_0016: ldc.i4.0
IL_0017: ret
IL_0018: ldarg.0
IL_0019: call valuetype System.Globalization.UnicodeCategory System.Globalization.CharUnicodeInfo::GetUnicodeCategory(char)
IL_001e: ldc.i4.8
IL_001f: ceq
IL_0021: ret
Т.е. на проверку каждого символа во-первых тратится время на вызов одной процедуры, в ней — на вызов еще двух. В общем надо попросить автора попробовать запустить этот пример и посмотреть на результаты.
2) IsDigit делает почти тоже, но не только тоже:
IL_0000: ldarg.0
IL_0001: call bool System.Char::IsLatin1(char)
IL_0006: brfalse.s IL_0018
IL_0008: ldarg.0
IL_0009: ldc.i4.s 48
IL_000b: blt.s IL_0016
IL_000d: ldarg.0
IL_000e: ldc.i4.s 57
IL_0010: cgt
IL_0012: ldc.i4.0
IL_0013: ceq
IL_0015: ret
IL_0016: ldc.i4.0
IL_0017: ret
IL_0018: ldarg.0
IL_0019: call valuetype System.Globalization.UnicodeCategory System.Globalization.CharUnicodeInfo::GetUnicodeCategory(char)
IL_001e: ldc.i4.8
IL_001f: ceq
IL_0021: ret
Т.е. на проверку каждого символа во-первых тратится время на вызов одной процедуры, в ней — на вызов еще двух. В общем надо попросить автора попробовать запустить этот пример и посмотреть на результаты.
public static bool IsDigit(char c)
{
if (!IsLatin1( c ))
return (CharUnicodeInfo.GetUnicodeCategory( c ) == UnicodeCategory.DecimalDigitNumber);
return c >= '0' && c <= '9';
}
* This source code was highlighted with Source Code Highlighter.
Так понятнее.
GetUnicodeCategory не выполнится если это не юникодовый символ, а проверка на юникодовость — функция IsLatin1 тоже будет инлайниться, т.к. у неё код ещё проще: «return (ch <= '\x00ff');»
В общем, не суть важно…
{
if (!IsLatin1( c ))
return (CharUnicodeInfo.GetUnicodeCategory( c ) == UnicodeCategory.DecimalDigitNumber);
return c >= '0' && c <= '9';
}
* This source code was highlighted with Source Code Highlighter.
Так понятнее.
GetUnicodeCategory не выполнится если это не юникодовый символ, а проверка на юникодовость — функция IsLatin1 тоже будет инлайниться, т.к. у неё код ещё проще: «return (ch <= '\x00ff');»
В общем, не суть важно…
Кстати, а как узнать инлайнился метод или нет?
Вот что выдаёт гугл:
The JIT uses a number of heuristics to decide whether a method should be in-lined. The following is a list of the more significant of those (note that this is not exhaustive):
* Methods that are greater than 32 bytes of IL will not be inlined.
* Virtual functions are not inlined.
* Methods that have complex flow control will not be in-lined. Complex flow control is any flow control other than if/then/else; in this case, switch or while.
* Methods that contain exception-handling blocks are not inlined, though methods that throw exceptions are still candidates for inlining.
* If any of the method's formal arguments are structs, the method will not be inlined.
www.ademiller.com/blogs/tech/2008/08/c-inline-methods-and-optimization/
The JIT uses a number of heuristics to decide whether a method should be in-lined. The following is a list of the more significant of those (note that this is not exhaustive):
* Methods that are greater than 32 bytes of IL will not be inlined.
* Virtual functions are not inlined.
* Methods that have complex flow control will not be in-lined. Complex flow control is any flow control other than if/then/else; in this case, switch or while.
* Methods that contain exception-handling blocks are not inlined, though methods that throw exceptions are still candidates for inlining.
* If any of the method's formal arguments are structs, the method will not be inlined.
www.ademiller.com/blogs/tech/2008/08/c-inline-methods-and-optimization/
ну, оно да, но вопросо в том сколько базовых операций выполняется и как быстро. В общем надо проверять что и как. Это в ассемблере еще можно было циклы считать… Пока не появилось распаралеливания, конвееров, и т.д.
Обожаю всякие такие тесты, спасибо :)
Странно, а я получил минусы там за коммент, в котором высказался за «понятливость» кода в сторону компилятора :)
Правда, смотрю теперь оценка 0 :)
Все же правда восторжествовала :)))
Правда, смотрю теперь оценка 0 :)
Все же правда восторжествовала :)))
Sign up to leave a comment.
Разбор полёта C# perfomance