Программирование мобильных устройств на платформе .NET Compact Framework - Иво Салмре
Шрифт:
Интервал:
Закладка:
//Запустить секундомер перед началом выполнения теста
PerformanceSampling.StartSample(2, "DefferedObjects");
//-----------------------------------------------
//БОЛЕЕ ЭКОНОМНЫЙ СПОСОБ: Распределить память для
//объекта до вхождения в цикл
//-----------------------------------------------
LessAllocationsWorkerClass workerClass1;
workerClass1 = new LessAllocationsWorkerClass();
int outerLoop;
for (outerLoop = 0; outerLoop < LOOP_SIZE; outerLoop++) {
//Присвоить элементам массива значения, которые
//мы хотим использовать при тестировании
ResetTestArray(ref testArray);
int topIndex = testArray.Length - 1;
for(int idx = 0; idx <= topIndex; idx++) {
//---------------------------------------------------------
//Более экономный способ:
//Теперь вместо повторного распределения памяти для объекта
//нам достаточно лишь повторно воспользоваться им
//Кроме того: в этом варианте реализации дополнительные
// строки НЕ создаются
//---------------------------------------------------------
//workerClass1 = new WastefulWorkerClass(
// testArray[topIndex]);
workerClass1.ReuseClass(testArray[idx]);
//Если средним словом является "blue", заменить его на "orange"
//--------------------------------------------------
//Более экономный способ:
//При таком способе сравнения не требуется создавать
//никаких дополнительных строк
//--------------------------------------------------
if (workerClass1.CompareMiddleSegment("blue") == 0) {
//Заменить средний сегмент workerClass1.MiddleSegment = "orange";
//Заменить слово
testArray[idx] = workerClass1.getWholeString();
}
}
}
//Остановить секундомер!
PerformanceSampling.StopSample(2);
System.Windows.Forms.MessageBox.Show(PerformanceSampling.GetSampleDurationText(2));
}
Листинг 8.8. Рабочий класс для третьего тестового примераusing System;
public class LessAllocationsWorkerClass {
public string MiddleSegment {
set { m_middleSegmentNew= value; }
}
private string m_middleSegmentNew;
private int m_index_1st_undscore;
private int m_index_2nd undscore;
private string m_stringIn;
public void ReuseClass(string in_word) {
//----------------------------------------------
//Для повторного использования класса необходимо
//полностью очистить внутреннее состояние
//----------------------------------------------
m_index_1st_undscore = -1;
m_index_2nd_undscore = -1;
m_middleSegmentNew= null;
m_stringIn = in_word; //Это не приводит к созданию копии строки
//Осуществляем поиск символов подчеркивания ("_") в строке
m_index_1st_undscore = in_word.IndexOf("_",0);
//B случае отсутствия символов "_" все, что нам нужно, это первый сегмент
if (m_index_1st_undscore == -1) {
return;
}
//Найти второй символ " "
m_index 2nd_undscore = in_word.IndexOf(" ", m_index_1st_undscore + 1);
}
public int CompareMiddleSegment(string compareTo) {
//B случае отсутствия второго символа "_" отсутствует и средний сегмент
if (m_index_2nd_undscore < 0) {
//Если мы сравниваем с пустой строкой,
//то это означает совпадение
if((compareTo == null) || (compareTo == "")) {return 0;}
return -1;
}
//Сравнить средний сегмент с первым и вторым сегментами
return System.String.Compare(
m_stringIn, m_index_1st_undscore + 1, compareTo, 0, m_index_2nd_undscore - m_index_1st_undscore -1);
}
public string getWholeString() {
//Если полученный средний сегмент не является новым,
//возвратить исходный сегмент
if (m_middleSegmentNew == null) {
return m_stringIn;
}
//Создать возвращаемую строку
return m_stringIn.Substring(0, m_index_1st_undscore + 1) +
m_middleSegmentNew +
m_stringIn.Substring(m_index_2nd_undscore, m_stringIn.Length - m_index_2nd_undscore);
}
}
Анализ описанных выше шагов последовательной оптимизации
Обычно в тонкой настройке алгоритмов таятся значительные резервы. Самое важное при этом — это контролировать, обеспечивает ли выполнение настройки выигрыш в производительности, на который вы рассчитывали. Некоторыми своими "усовершенствованиями" вы можете непреднамеренно ухудшить производительность из-за того, что с ними связано распределение памяти, о котором вы можете не знать, или в силу каких-либо других причин. В процессе разработки приведенного выше кода у меня несколько раз возникали ситуации, когда я считал, что вносимые изменения должны улучшить результаты, но после проведения соответствующих измерений и при более глубоком рассмотрении оказывалось, что эти изменения приносили только вред. Всегда измеряйте показатели производительности и проводите их сравнительный анализ для различных вариантов реализации!
Кроме того, очень важно проводить тестирование на фактическом оборудовании, для которого предназначено ваше приложение, чтобы лучше почувствовать реальные условия работы с ним "на устройстве". Эмуляторы очень удобно использовать в процессе проектирования и базовой настройки приложения, но результаты, полученные на физическом устройстве, могут быть другими из-за различий в свойствах процессоров, памяти и других факторов. Одни программы могут выполняться на физических устройствах быстрее, другие — медленнее. Последнее слово всегда остается за фактическим оборудованием, которое будут использовать конечные пользователи. По тем же причинам очень важно измерять производительность при выполнении программы с подключенным отладчиком и без него. В некоторых случаях подключение отладчика резко снижает производительность.
Результаты тестирования трех различных алгоритмов, обсуждаемых нами, представлены в таблицах 8.1 и 8.2.
Таблица 8.1. Результаты тестирования алгоритмов (в секундах) на эмуляторе Pocket PC с вычислением 8000 циклов
Порядковый номер теста Неэкономное распределение памяти Незначительное уменьшение объема распределяемой памяти Значительное уменьшение объема распределяемой памяти 1 12,65 12,2 8,925 2 12,775 12,35 8,55 3 12,575 12,25 8,225 4 12,625 12,525 8,575 Среднее 12,65625 12,33125 8,56875 Экономия времени по сравнению с базовым уровнем 0% 2,57% 32,30%Таблица 8.2. Результаты тестирования алгоритмов (в секундах) на физическом устройстве Pocket PC с вычислением 2000 циклов
Порядковый номер теста Неэкономное распределение памяти Незначительное уменьшение объема распределяемой памяти Значительное уменьшение объема распределяемой памяти 1 30,609 30,151 20,484 2 30,538 30,016 20,362 3 30,517 30,195 20,377 4 30,457 30,316 20,429 Среднее 30,53025 30,1695 20,413 Экономия времени по сравнению с базовым уровнем 0% 1,18% 33,14%Анализ приведенных выше результатов говорит о следующем:
■ Применение первого варианта оптимизации, основанного на повторном использовании объектов вместо распределения памяти, обеспечило лишь самое минимальное повышение производительности. Вероятно, такое поведение приложения объясняется небольшими размерами самих объектов и используемых данных. Уже зная полученные результаты, можно отметить, что в них нет ничего удивительного. Учитывая легкость проведения этого вида оптимизации, который требует включения всего лишь нескольких новых строк кода, он заслуживает интереса. Дополнительным преимуществом этого способа, которое не отражают приведенные выше цифры, является то, что исключение размещения в памяти новых объектов из цикла с большим количеством повторений должно приводить к значительному уменьшению "объектного мусора" в нашем приложении. В результате этого сборка мусора будет осуществляться реже, следствием чего должно быть значительное улучшение общей производительности. Этот вид оптимизации не привел к существенному повышению скорости выполнения приложения, но и не ухудшил ее, а, кроме того, обеспечил значительное уменьшение объема образующегося "мусора".