Министерство образования и науки Российской Федерации
Министерство образования Саратовской области
Национальный исследовательский Саратовский государственный университет имени Н.Г. Чернышевского
Саратовский областной институт развития образования
Комитет по информатизации Саратовской области
Комитет по образованию администрации муниципального образования «Город Саратов»
Автономная некоммерческая организация «Информационные технологии в образовании»
Автономная некоммерческая организация «Научно-исследовательский центр «Образование. Качество. Отрасль»»
IX Всероссийская (с международным участием) научно-практическая конференция
«Информационные технологии в образовании»
«ИТО-Саратов-2017»
2-3 ноября 2017 года, г. Саратов

ОПТИМИЗАЦИЯ ПРОГРАММНОГО КОДА С ИСПОЛЬЗОВАНИЕМ СРЕДСТВ ПРОФИЛИРОВАНИЯ VISUAL STUDIO

Саратовский национальный исследовательский государственный университет имени Н. Г. Чернышевского

В современном мире разработка программного обеспечения (ПО) превратилась в одну из самых дорогостоящих индустрий. Любые недочеты и ошибки в процессе создания ПО могут привести к нежелательным результатам, поэтому разработка «совершенного кода» очень важна. Очевидно, что такой код должен быть оптимальным.

В большинстве случаев даже правильно работающий код, написанный студентом, может быть усовершенствован. Причина заключается в том, что выбранный студентом алгоритм является базовым, и при его реализации на конкретном языке программирования не в полной мере учитываются условия поставленной задачи, специфика языка программирования и схемы трансляции. Студенту недостаточно знать базовые алгоритмы и их теоретическую сложность, уметь программировать, нужно уметь оценивать реальное время выполнения программ [1], владеть инструментальными средствами, позволяющими определять проблемы производительности на уровне исходного кода, а также знать методики оптимизации кода и уметь применять их на практике [2].

В данной статье будет представлена методическая разработка по использованию средств профилирования Visual Studio Community 2017 (VS) для оптимизации программного кода, написанного на языке С# [3].

Исходная постановка задачи [4]: Разработать программу, позволяющую определить является ли текст «красивым».

Текст называется красивым, если он состоит из ненулевого числа красивых предложений, разделенных одним пробелом.

Предложение называется красивым, если оно представляет собой непустую последовательность слов, разделенных одним пробелом, заканчивается точкой, многоточием (из ровно трех точек), знаком вопроса или восклицательным знаком. Вместо пробела между словами может находиться знак препинания, а именно строка «, », «; », « - » или «, - ». Первое слово в предложении должно начинаться с заглавной буквы.

Слово называется красивым, если оно состоит из одной или двух частей, разделенных одним дефисом. В каждой части все буквы должны быть строчными латинскими, а первая буква может быть заглавной латинской. Длина части должна быть не меньше 1. Кроме того, слово, состоящее из одной части, может быть аббревиатурой, то есть состоять исключительно из заглавных латинских букв.

Пример красивого текста:«This program is free-software; you can copy it.»

Пример некрасивого текста:«i cannot write bEaUtIfUl sentences :(((».

Решение данной задачи основывается на использовании регулярных выражений [5] и Linq-запросов [6]. Фрагмент исходного кода программы представлен ниже:

public static bool CheckText(string textcase)

 {  //Создается массив предложений с помощью регулярных выражений

    string[] sentences = new Regex(@"(?<=[\.\!\?])\s+").Split(textcase);

    foreach (string sentence in sentences)

     { //Cоздаются массивы слов и разделителей с помощью регулярных выражений

        string[] words = new Regex(@"[^A-Za-z\-]+")

             .Split(sentence).Where(x => x != "").ToArray();

       string[] separators = new Regex(@"[A-Za-z\-]+")

             .Split(sentence).Where(x => x != "").ToArray();

       // Проверка на корректность разделителей

        if(separators

              .Take(separators.Length - 1).Any(x => !new Regex(@"(, - | - |, |; | ").IsMatch(x)))

           { continue; }

         // Проверка последних символов

         if(!newRegex(@"(\.{3}|[\.\?!])").IsMatch(separators.Last()))

             { continue; }

         // Проверка на корректность слов

         if(words.Skip(1) .Any(x=>

              !new Regex(@"^([A-Z][A-Z]*|[A-Za-z]([a-z]+(\-[a-z]{2,})?)?)$").IsMatch(x)))

             { continue; }

         // Проверка первого слова

         if(newRegex(@"^([A-Z][A-Z]*|[A-Z]([a-z]+(\-[a-z]{2,})?)?)$")

              .IsMatch(words.First()))

            { return true; }

        }

    return false;

}

Использования средств профилирования VS начинается с настройки сеанса анализа производительности. Для этой цели нужно открыть код программы (решение) в среде VS. Выбрать конфигурацию «Выпуск»/«Release» (запуск от имени администратора).  

Для запуска процесса сбора данных о производительности в меню «Анализ» необходимо выбрать «Профилировщик производительности», установить флажок «Мастер производительности» и нажать кнопку «Запуск». Установить флажок «Выборка циклов ЦП» или «Инструментирование» и нажать кнопку «Готово». Исследуемое решение запускается, и VS начинает собирать данные о его производительности в реальном времени, которые записываются в специальный файл (*.vsp). После завершения сбора данных файл с отчетом отображается в окне «Отчет о производительности». Для нашего решения мы получили следующий отчет о производительности (рис.1).

Рисунок 1 –  Фрагмент отчета о производительности

Анализируя полученные данные, можно сделать вывод о том,  что максимальное время затрачивается на создание регулярного выражения (55,56 % времени работы центрального процессора). Если щелкнуть на имя данного метода, то откроется код решения, в котором красной линией будет выделен участок кода, требующий оптимизации. В нашем случае был подсвечен фрагмент кода, который на каждой итерации цикла создавал одно и тоже регулярное выражение newRegex(@"...").

Применив методику оптимизации кода «Минимизация объема работы, выполняемой внутри цикла» [2], вынесем создание всех регулярных выражений за цикл. Измененный код нашего решения теперь выглядит следующим образом:

public static bool CheckText(string textcase)

 {  //Создается массив предложений с помощью регулярных выражений

     string[] sentences = new Regex(@"(?<=[\.\!\?])\s+").Split(textcase);

      //Cоздается регулярное выражение для проверки слов в предложении

      Regex CheckWords = new Regex(@"^([A-Z][A-Z]*|[A-Za-z]([a-z]+(\-[a-z]{2,})?)?)$");   

      //Cоздается регулярное выражение для проверки первого слова в предложении  

      Regex CheckFirstWord = new Regex(@"^([A-Z][A-Z]*|[A-Z]([a-z]+(\-[a-z]{2,})?)?)$"); 

      //Cоздается регулярное выражение для проверки знака препинания в конце предложения

      RegexCheckLastSeparators= newRegex(@"(\.{3}|[\.\?\!])");

      //Cоздается регулярное выражение для проверки знаков препинания внутри предложения

      RegexCheckdelimiters= newRegex(@"(, - | - |, |; | )");

      //Создаются регулярные выражения для разбиения предложения на слова и разделители

      Regex wordsR = new Regex(@"[^A-Za-z\-]+");

      Regex separatorsR = new Regex(@"[A-Za-z\-]+");

      foreach (string sentence in sentences)

       {   //Cоздаются массивы слов и разделителей с помощью регулярных выражений

            string[] words = wordsR.Split(sentence).Where(x => x != "").ToArray();

            string[] separators = separatorsR.Split(sentence).Where(x => x != "").ToArray();

            // Проверка на корректность разделителей

            if (separators.Take(separators.Length - 1)

                .Any(x => !Checkdelimiters.IsMatch(x)))  { continue; } 

            // Проверка последних символов

            if (!CheckLastWord.IsMatch(separators.Last())) { continue; }                          

            // Проверка на корректность слов

            if (words.Skip(1).Any(x => !CheckWords.IsMatch(x))) {  continue; }

            // Проверка первого слова

            if (CheckFirstWord.IsMatch(words.First()))  {  return true; }

       }

 }

Чтобы убедиться в том, что внесенные в код решения изменения привели к его оптимизации, повторно запустим профилировщик производительности. Получим новый отчет о производительности. Затем в меню «Отчеты» выберем пункт «Сравнить отчеты о производительности», указав в качестве базового файла исходный отчет о производительности, в качестве файла сравнения – новый отчет о производительности (рис.2).

По полученным данным, можно сделать вывод, что наши действия, направленные на оптимизацию кода, оказались успешны (успешные позиции в отчеты отмечены зелеными стрелками).

Рисунок 2 – Сравнение отчетов

Дополнительно нами проводились замеры реального время выполнения исходной и оптимизированной программы, которые показали, что время выполнения оптимизированной программы сократилось в 4 раза.

В заключение следует отметить, что средства профилирования VS – удобное и доступное для студентов и преподавателей вузов решение проблемы поиска помощника в написании совершенного кода. Обучение студентов навыкам использования профилировщика VS для оптимизации программного кода поможет студентам в их будущей профессиональной деятельности. 

Список использованных источников
  1. Кудрина Е.В., Кузьмина В.Р. Роль оценки реального времени выполнения программы на примере алгоритмов поиска делителей натурального числа// Информационные технологии в образовании: Материалы VII Всерос.научно-практ. конференции. – Саратов: ООО «Издательский центр «Наука», 2015. – С. 49-54.
  2. Макконнелл С. Совершенный код. Мастер – класс / Пер. с англ – М.: Издательство «Русская редакция», 2010. – 896 стр.:ил.
  3. Средства профилирования [Электронный ресурс] // Microsoft Developer Network.– URL: https://msdn.microsoft.com/ru-ru/library/ms182371.aspx (дата обращения: 10.09.2017).
  4. Задача D «Красивый текст» [Электронный ресурс]// Летняя компьютерная школа 2013. Регулярные выражения. URL: http://hist.leenr.ru/camps/lksh/2013.Winter/ejudge.lksh.ru/C/05/problems.pdf (дата обращения: 10.09.2017).
  5. Черноусова Ю.А., Кудрина Е.В. Применение регулярных выражений при решении школьных олимпиадных задач по информатике//Информационные технологии в образовании: Материалы VIII Международн. научно-практ. конференции. – Саратов: ООО «Издательский центр «Наука», 2016. – С. 125-129.
  6. Огнева М.В., Кудрина Е.В. Программирование в среде Visual Studio .Net: разработка приложений на языке C#. – Саратов: Издательство «КУБиК», 2010. – 545 с.
Вид представления доклада  Устное выступление и публикация

В статусе «Черновик» Вы можете производить с тезисами любые действия.

В статусе «Отправлено в Оргкомитет» тезисы проходят проверку в Оргкомитете. Статус «Черновик» может быть возвращен тезисам либо если есть замечания рецензента, либо тезисы превышают требуемый объем, либо по запросу участника.

В статусе «Рекомендован к публикации» тезис публикуется на сайте. Статус «Черновик» может быть возвращен либо по запросу участника, либо при неоплате публикации, если она предусмотрена, либо если тезисы превышают требуемый объем.

Статус «Опубликован» означает, что издана бумажная версия тезиса и тезис изменить нельзя. В некоторых крайне редких ситуацих участник может договориться с Оргкомитетом о переводе тезисов в статус «Черновик».

Статус «Отклонен» означает, что по ряду причин, которые указаны в комментариях к тезису, Оргкомитет не может принять тезисы к публикации. Из отклоненных тезис в «Черновики» может вернуть только Председатель программного или председатель оргкомитета.