Общие шаблоны для неправильно работающих многопоточных приложений
Визуализатор параллелизма помогает разработчикам визуализировать поведение многопоточного приложения. В этом средстве предусмотрена коллекция общих шаблонов для нескольких многопоточных приложений с неправильным поведением. В коллекции содержатся типичные узнаваемые визуальные шаблоны, которые реализуются с помощью данного средства, а также объяснение поведения, представленного каждым шаблоном, вероятный результат такого поведения и наиболее распространенные способы его устранения.
Конфликт блокировок и сериализованное выполнение
Иногда распараллеленное приложение продолжает выполняться последовательно, несмотря на наличие нескольких параллельных потоков и достаточного количества логических ядер у компьютера. Первый симптом — низкая многопоточная производительность, возможно даже ниже, чем при последовательной реализации. В представлении потоков не видно параллельного выполнения нескольких потоков, вместо этого в любой момент времени выполняется только один поток. Если щелкнуть здесь сегмент синхронизации в потоке, отобразится стек вызовов, блокирующий поток (блокирующий стек вызовов), а также поток, удаляющий блокирующее условие (разблокирующий стек вызовов). Кроме того, если в анализируемом процессе возник разблокирующий стек вызовов, отобразится соединитель для потока. Далее можно переходить к коду от блокирующих и разблокирующих стеков вызова, чтобы установить причину сериализации.
Как показано на следующем рисунке, визуализатор параллелизма может также обнаруживать подобные признаки в представлении использования ЦП, когда, несмотря на наличие нескольких потоков, приложение использует только одно логическое ядро.
Дополнительные сведения см. в разделе "Начало работы с проблемой" статьи MSDN Magazine Thread Performance — Resource Contention Concurrency Profiling in Visual Studio.
Неравномерное распределение рабочей нагрузки
При неравномерном распределении рабочей нагрузки между несколькими параллельными потоками в приложении по мере завершения каждого потока образуется своеобразная лестница, как показано на изображении выше. Обычно время запуска всех параллельных потоков в визуализаторе параллелизма практически совпадает. Однако заканчиваются эти потоки обычно не одновременно, а произвольным образом. Этот шаблон показывает неравномерное распределение работы между группами параллельных потоков, что может ухудшать производительность. Лучший способ решения этой проблемы — переоценка алгоритма, по которому рабочая нагрузка распределяется между параллельными потоками.
Как показано на следующем рисунке, эти признаки могут проявляться в визуализаторе параллелизма в представлении использования ЦП в виде поэтапного снижения уровня использования центрального процессора.
Превышение лимита подписки
В случае превышения лимита подписки число активных потоков процесса превышает число доступных ядер системы. На предыдущем рисунке показаны результаты превышения лимита подписки с явно выраженным наличием приоритетного прерывания во всех активных потоках. Кроме того, на легенде показано, что на приоритетное прерывание затрачена значительная доля времени (84 процента в данном примере). Это может свидетельствовать о том, что количество параллельных потоков, запрашиваемых процессом в системе, превышает число логических ядер. Однако это может также свидетельствовать о том, что ресурсы, которые предположительно должны были быть доступными для данного процесса, используются в системе другими процессами.
При анализе данной проблемы нужно учитывать следующие особенности.
Возможно, превышение лимита подписки является общесистемной проблемой. Следует учитывать, что приоритетное прерывание потоков данного процесса может также инициироваться другими процессами в системе. Если навести указатель на сегмент приоритетного прерывания в представлении потока, отобразится подсказка с указанием потока и процесса, которые инициировали такое прерывание данного потока. Инициировавший прерывание процесс не обязательно выполняется все время, в течение которого данный процесс не выполнялся вследствие приоритетного прерывания, однако эти сведения позволяют определить источник избыточных приоритетных прерываний процесса.
Проанализируйте принцип определения процессом надлежащего числа потоков для выполнения на этом этапе работы. Если процесс непосредственно вычисляет число активных параллельных потоков, попытайтесь изменить алгоритм, усовершенствовав подсчет числа доступных в системе логических ядер. Если используется среда выполнения с параллелизмом, библиотека параллельных задач (Task Parallel Library) или PLINQ, эти библиотеки выполняют вычисление количества потоков.
Неэффективный ввод-вывод
Избыточное или недостаточное использование ввода-вывода обычно приводит к неэффективности работы приложений. Рассмотрим предыдущий рисунок. В профиле видимой временной шкалы указано, что 44 процента видимого времени выполнения приложений потрачено на ввод-вывод. На временной шкале указано много операций ввода-вывода, что свидетельствует о частом блокировании ввода-вывода в профилируемом приложении. Чтобы просмотреть подробные сведения о характере операций ввода-вывода и блокировании программы, увеличьте проблемные области, проанализируйте профиль видимой временной шкалы, а затем щелкните определенный блок ввода-вывода, чтобы просмотреть текущие стеки вызова.
Колонны блокировок
Колонны блокировок возникают, когда приложение получает блокировки в порядке поступления запросов и когда скорость прибытия на блокировку превышает скорость получения блокировок. При сочетании этих двух условий блокировки начинают резервироваться. Один из способов устранения этой проблемы заключается в использовании "нечестных" блокировок или блокировок, которые предоставляют доступ первому потоку, чтобы он мог перейти в разблокированное состояние. На предыдущем рисунке показано такое построение в колонну. Для решения этой проблемы попытайтесь снизить число конфликтов при синхронизации объектов и прибегнуть к "нечестным" блокировкам.