■ Измеряйте объективные количественные показатели своих алгоритмов. Занимаясь написанием алгоритма обработки строк, тестируйте его быстродействие! Испробуйте несколько различных подходов. Вы очень быстро научитесь распознавать, какой алгоритм будет эффективным, а какой — нет.
Пример эффективного создания строк
В листинге 8.9 представлены два аналогичных алгоритма, которые приводят к одному и тому же результату. В обоих алгоритмах осуществляется инкрементирование счетчика, и каждый раз, когда значение счетчика увеличивается, его строковое представление добавляется в расширяемый фрагмент текста. Оба алгоритма выполняют одинаковое количество итераций и характеризуются одинаковой степенью сложности написания. И, тем не менее, один из них работает гораздо быстрее другого.
Листинг 8.9. Сравнение эффективности использования строк и класса StringBuilder в алгоритмах
Примечание. В этом примере используется класс PerformanceSampling, определенный ранее в данной книге.
const int COUNT_UNTIL = 300;
const int LOOP_ITERATIONS = 40;
//---------------------------------------------------------
//HE ОЧЕНЬ ЭФФЕКТИВНЫЙ АЛГОРИТМ!
//
//Для имитации создания типичного набора строк используются
//обычные строки
//---------------------------------------------------------
private void button1_Click(object sender, System.EventArgs e) {
//Вызвать сборщик мусора, чтобы тест //начинался с чистого состояния.
//ПРИБЕГАЙТЕ К ЭТОЙ МЕРЕ ТОЛЬКО В ЦЕЛЯХ ТЕСТИРОВАНИЯ! Вызовы
//сборщика мусора в программах вручную будут приводить
//к снижению общей производительности приложений!
System.GC.Collect();
int numberToStore = 0;
PerformanceSampling.StartSample(0, "StringAllocaitons");
string total_result = "";
for (int outer_loop = 0; outer loop < LOOP_ITERATIONS; outer_loop++) {
//Сбросить старый результат total_result = "";
//Выполнять цикл до максимального значения x_counter, каждый
//раз присоединяя очередную тестовую строку к рабочей строке
for (int x_counter = 0; x_counter < COUNT_UNTIL; x_counter++) {
total_result = total_result + numberToStore.ToString() + ", ";
//Увеличить значение счетчика
numberToStore ++;
}
}
PerformanceSampling.StopSample(0); //Отобразить длину строки
System.Windows.Forms.MessageBox.Show("Длина строки: " + total_result.Length.ToString());
//Отобразить строку
System.Windows.Forms.MessageBox.Show("Строка : " + total_result);
//Отобразить длительность интервала времени, ушедшего на вычисления
System.Windows.Forms.MessageBox.Show(PerformanceSampling.GetSampleDurationText(0));
}
//---------------------------------------------------------
//ГОРАЗДО БОЛЕЕ ЭФФЕКТИВНЫЙ АЛГОРИТМ!
//
//Для имитации создания типичного набора строк используется
//объект StringBuilder
//---------------------------------------------------------
private void button2_Click(object sender, System.EventArgs e) {
//Вызвать сборщик мусора, чтобы тест
//начинался с чистого состояния.
//ПРИБЕГАЙТЕ К ЭТОЙ МЕРЕ ТОЛЬКО В ЦЕЛЯХ ТЕСТИРОВАНИЯ! Вызовы
//сборщика мусора в программах вручную будут приводить
//к снижению общей производительности приложений!
System.GC.Collect();
System.Text.StringBuilder sb = new System.Text.StringBuilder();
string total_result = "";
int numberToStore = 0;
PerformanceSampling.StartSample(1, "StringBuilder");
for (int outer_loop = 0; outer_loop < LOOP_ITERATIONS; outer_loop++) {
//Очистить объект StringBuilder (не создавая нового объекта)
sb.Length = 0;
//Очистить строку со старым результатом
total_result = "";
//Выполнять цикл до максимального значения x_counter, каждый раз
//присоединяя очередную тестовую строку к рабочей строке
for (int x_counter = 0; x_counter < COUNT_UNTIL; x_counter++) {
sb.Append(numberToStore);
sb.Append(", ");
//Увеличить значение счетчика
numberToStore++;
}
//Имитируем выполнение некоторых операций над строкой...
total_result = sb.ToString();
}
PerformanceSampling.StopSample(1);
//Отобразить длину строки
System.Windows.Forms.MessageBox.Show("Длина строки: " + total_result.Length.ToString());
//Отобразить строку
System.Windows.Forms.MessageBox.Show("String : " + total_result);
//Отобразить длительность интервала времени, ушедшего на вычисления
System.Windows.Forms.MessageBox.Show(PerformanceSampling.GetSampleDurationText(1));
}
Таблица 8.3. Сравнение результатов (в секундах) для 40×300 циклов, выполненных с использованием эмулятора
Порядковый номер теста |
Неэкономное распределение памяти для строк |
Использование класса StringBuilder |
1 |
25,475 |
0,85 |
2 |
25,225 |
0,925 |
3 |
24,5 |
0,875 |
Среднее |
25,07 |
0.88 |
Экономия времени по сравнению с базовым уровнем |
0% |
96,5% |
Таблица 8.4. Сравнение результатов (в секундах) для 40×300 циклов, выполненных на физическом устройстве Pocket PC
Читать дальше