Rose debug info
---------------

String и StringBuilder

Недавно отпимизировал алгоритм: раньше он работал 18 минут. Сейчас 0.4 секунды. Было необходимо сделать для сайта sitemap, дабы скормить его поисковым гиганатам. В таблице базы данных содержалось всего 18 000 строк, и алгоритм пробегал по ней за 18 минут, и делалось это вот так:

string GenerateSmap() 

{ 

string strResult = "";

SqlConnection SQLDB;

SqlCommand SQLDBCMD;

SqlDataReader SqlR;

SQLDB = new SqlConnection(strConn);

SQLDBCMD = new SqlCommand("SELECT id_article, article_num FROM articles", SQLDB);

SQLDB.Open();

SqlR = SQLDBCMD.ExecuteReader();

while (SqlR.Read())

{ 

    strResult = strResult + ("<url>\r\n");

    strResult = strResult + ("<loc>http://www.kazved.ru/article/" + SqlR["id_article"] + ".aspx</loc>\r\n)");

    strResult = strResult + ("<changefreq>monthly</changefreq>\r\n");

    strResult = strResult + ("<priority>0.8</priority>\r\n"); strResult = strResult + ("</url>\r\n");

} 

SqlR.Close();

SQLDB.Close();

return strResult;

}

Представляете, 18 (!!!) минут! это целую минуту на каждую 1000 строк! Дело заключается не в SQL, а в «strResult = strResult + ...». Дело в том, что, каждый раз, когда мы обращаемся к System.String, мы каждый раз создаем новый объект string в памяти. Это сильно замедляет процесс, если вы часто делаете повторяющиеся изменения в стринге. Для этих целей горздо продуктивнее использовать класс System.Text.StringBuilder, он не создает новый объект в памяти, а оперирует уже имеющимся. В данном примере, использование StringBuilder будет таким:

string GenerateSmap() { StringBuilder strResult = new StringBuilder(); 

...

        while (SqlR.Read()) 

        { 

             strResult.Append("<url>\r\n"); strResult.Append("<loc>http://www.kazved.ru/article/" + SqlR["id_article"] + ".aspx</loc>\r\n)"); 

             strResult.Append("<changefreq>monthly</changefreq>\r\n"); strResult.Append("<priority>0.8</priority>\r\n"); strResult.Append("</url>\r\n");

        }

... 

return strResult.ToString(); 

}

После такого преобразования, функция стала выполняться не 18 минут, а 0.4 секунды! Мы имеем ускорение в 2700 раз!Кстати, при сооздании StringBuilder’a, вы можете задать его размер, прописав свойство Capacity, или используя оверлоад:

MyStringBuilder.Capacity = 25; 
StringBuilder MyStringBuilder = new StringBuilder("Hello World!", 25);

Так же, можно прочитать и задать его длину, для этого используется свойство Length. Если вы здаете Length больше чем Capacity, то Capacity увеличится и станет равным Length. А если вы зададите Length меньше чем длина строки, что находится в StringBuilder’е, стринг билдер сам уменьшит эту строку.

Редактирование строки в StringBuilder.
Для редактирование строк в StringBuilder есть 5 методов: StringBuilder.Append, StringBuilder.AppendFormat, StringBuilder.Insert, StringBuilder.Remove, StringBuilder.Replace Названия у них говорят сами за себя, примеры использования простые. Метод StringBuilder.Append добавляет данные в конец строки, уже показывал в начале статьи, но пусть еще раз:

StringBuilder MyStringBuilder = new StringBuilder("Йа "); 
MyStringBuilder.Append("креведко");
Console.WriteLine(MyStringBuilder);
StringBuilder.AppendFormat делает тоже самое что и Append, но еще применяет IFormattable, который принимает стандартные шаблоны форматирования.
int MyInt = 25; 
StringBuilder MyStringBuilder = new StringBuilder("На ашем счету ");
MyStringBuilder.AppendFormat("{0:C} ", MyInt); 
Console.WriteLine(MyStringBuilder);
StringBuilder.Insert делает вставку в текстовую строку в указанном месте:
StringBuilder MyStringBuilder = new StringBuilder("Hello World!");
MyStringBuilder.Insert(6,"Beautiful ");
Console.WriteLine(MyStringBuilder);
StringBuilder.Remove удаляет в указанном месте указанное количество символов:
StringBuilder MyStringBuilder = new StringBuilder("Hello World!"); 
MyStringBuilder.Remove(5,7); //с 5го по 7ой, нумерация идет от 0 
Console.WriteLine(MyStringBuilder);
StringBuilder.Replace просто заменяет указанные символы на другие:
StringBuilder MyStringBuilder = new StringBuilder("Hello World!");
MyStringBuilder.Replace('!', '?');
Console.WriteLine(MyStringBuilder);
4 комментария
Boglen 2007

Тру, взял на заметку.

XAP 2007

Нашет тут моленькие подскозки для себя, спасибо.

PetoN 2008

РЕспект за статью, я уж думал все, нужно другой язык программирования учить или еще что то в этом проде .... просто не знал принципа работы Стринг ..

Aleksey Baryshnikov 2009

Большое спасибо, очень полезная информация