Параллельное программирование – это способ написания программ, которые могут выполняться параллельно на нескольких процессорах или ядрах. Это позволяет программам обрабатывать большие объемы данных или выполнить более сложные вычисления за приемлемое время, чем это было бы возможно на одном процессоре. Преимущества параллельного программирования: увеличение производительности, распределение нагрузки, обработка больших объемов данных, улучшение отзывчивости, увеличение надежности. В целом, параллельное программирование имеет множество преимуществ, которые могут помочь улучшить производительность и надежность программных систем, особенно в условиях растущей сложности вычислительных задач и объемов данных. Однако параллельное программирование также может иметь свои сложности, связанные с управлением синхронизацией, гонками данных и другими аспектами, которые требуют дополнительного внимания и опыта со стороны программиста. В ходе тестирования параллельных программ можно получить неоднозначные результаты. Например, это может происходить, когда мы оптимизируем объединение данных типа float
или double
посредством методов For
или ForEach
класса Parallel
. Подобное поведение программы заставляет усомниться в потокобезопасности написанного кода. Пост раскрывает возможную причину неоднозначности результатов, получаемых параллельной программой, и предлагает лаконичное решение вопроса.
-
посты
-
Неоднозначность результатов при использовании методов класса Parallel в рамках исполняющей среды .NET Framework
-
Потокобезопасные вызовы элементов управления в приложениях WPF, UWP и Windows Forms
Многопоточность может повысить производительность в приложениях Windows Presentation Foundation (WPF), Universal Windows Platform (UWP) и Windows Forms, но доступ к элементам управления не является потокобезопасным. Не потокобезопасный код может стать причиной для серьезных и сложных ошибок. Два или более потока, оказывающих влияние на элемент управления, могут привести к нестабильному состоянию приложения и вызвать условия состязаний. Данный пост посвящен раскрытию темы вызова элементов управления пользовательского интерфейса потокобезопасным образом, в частности объяснению понятия “контекст синхронизации”.
-
Сборник рецептов по регулярным выражениям
Язык регулярных выражений распознает символьные образцы. Типы .NET, поддерживающие регулярные выражения, основаны на регулярных выражениях Perl 5 и обеспечивают функциональность как поиска, так и поиска/замены. Регулярные выражения используются для решения следующих задач: проверка текстового ввода, такого как пароли и телефонные номера; преобразование текстовых данных в более структурированные формы (например, извлечение данных из HTML-страницы с целью их сохранения в базе данных); замена образцов текста в документе (например, только целых слов). В посте раскрываются аспекты применения языка регулярных выражений в виде сборника рецептов.
-
Исключения в задачах
В отличие от потоков задачи без труда распространяют исключения. Таким образом, если код внутри задачи генерирует необработанное исключение (другими словами, если задача отказывает), то это исключение автоматически повторно сгенерируется при вызове метода
Wait
или доступе к свойствуResult
классаTask<TResult>
. В посте детально раскрывается механизм обработки данных исключений. -
Планировщик задач
Планировщик задач распределяет задачи по потокам и представлен абстрактным классом
TaskScheduler
. В .NET Framework предлагаются две конкретные реализации: стандартный планировщик, который работает в тандеме с пулом потоков CLR, и планировщик контекста синхронизации. Последний предназначен для содействия в работе с потоковой моделью WPF и Windows Forms, которая требует, чтобы доступ к элементам управления пользовательского интерфейса осуществлялся только из создавшего их потока. В данном посте представлен механизм работы стандартного планировщика. -
Счетчики производительности
Счетчики производительности сгруппированы в категории, такие как “Система”, “Процессор”, “Память .NET CLR” и т.д. Примерами счетчиков производительности в категории “Память .NET CLR” могут быть “% времени сборки мусора”, “# байтов во всех кучах” и “Выделено байтов/с”. Каждая категория может дополнительно иметь один или более экземпляров, допускающих независимый мониторинг. Это полезно, например, для счетчика производительности “% процессорного времени” из категории “Процессор”, который позволяет отслеживать утилизацию центрального процессора. На многопроцессорной машине данный счетчик поддерживает экземпляры для всех процессоров, позволяя независимо проводить мониторинг использования каждого процессора. В посте демонстрируются программы по перечислению и чтению доступных счетчиков производительности, а также по созданию специализированных счетчиков и записи в них данных.
-
Утечки управляемой памяти при реализации событий
В посте показано, каким образом события могут вызывать утечки управляемой памяти. Предлагаются два решения, чтобы избежать подобных утечек. Первое решение связано с реализацией метода
Dispose
для отмены подписки, во втором решении демонстрируется применение слабых ссылок. -
Проблемы кэшируемой памяти
Раскрывается приём работы с кэш-памятью, обеспечивающий эффективную работу приложения по критерию быстродействия в многопоточном сценарии.
-
Параллельная программа проверки орфографии
Предлагается программа проверки орфографии, которая выполняется быстро для документов большого объема за счет использования всех свободных процессорных ядер.
-
Освобождение "ненужных" объектов при использовании LazyInitializer
Ленивая инициализация это способ доступа к объекту, скрывающий за собой механизм, позволяющий отложить создание этого объекта до момента первого обращения к нему. Класс
LazyInitializer
обеспечивает ленивую инициализацию разделяемого поля в безопасной к потокам манере. Однако, в ходе применения данного класса могут создаваться лишние объекты. В посте предлагается решение по освобождению “ненужных” объектов, которые создаются в ходе применения классаLazyInitializer
для ленивой инициализации в многопоточном сценарии.