Многопоточность, асинхроность

Содержание

Слайд 2

Однопоточность

Система в одном потоке работает со всеми задачами, выполняя их поочерёдно.

Однопоточность Система в одном потоке работает со всеми задачами, выполняя их поочерёдно.

Слайд 3

Многопоточность

В этом случае речь о нескольких потоках, в которых выполнение задач идет

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

Слайд 4

Асинхронность

Характеристики асинхронного кода:
обрабатывает больше запросов сервера, предоставляя потокам возможность обрабатывать больше запросов

Асинхронность Характеристики асинхронного кода: обрабатывает больше запросов сервера, предоставляя потокам возможность обрабатывать
во время ожидания результата от запросов ввода-вывода;
делает пользовательский интерфейс быстрым, выделяя потоки для обработки действий в пользовательском интерфейсе во время ожидания запросов ввода-вывода, передавая затратные по времени операции другим ядрам ЦП.

Слайд 5

Многопоточность VS Асинхронность

Многопоточность — параллельное выполнение, асинхронность — логическая оптимизация выполнения, которая

Многопоточность VS Асинхронность Многопоточность — параллельное выполнение, асинхронность — логическая оптимизация выполнения,
может работать и в одном, и во многих потоках.

Слайд 6

Проблемы многопоточности

Многозадачность
Вытесняющая
Кооперативная
Проблемы планирования задач
Переключение контекста
Приоритеты
Общая память
Условия гонок (race condition)
Взаимная блокировка (deadlock)

Проблемы многопоточности Многозадачность Вытесняющая Кооперативная Проблемы планирования задач Переключение контекста Приоритеты Общая

Слайд 7

Асинхронный код в .NET

В .NET-фреймворке исторически сложилось несколько более старых паттернов организации

Асинхронный код в .NET В .NET-фреймворке исторически сложилось несколько более старых паттернов
асинхронного кода:
APM (IAsyncResult, они же коллбеки) (.NET 1.0).
EAP — события, этот паттерн все видели в WinForms (.NET 2.0).
TAP (Task Asynchronous Pattern) — класс Task и его экосистема (.NET 4.0).

Слайд 8

Класс System.Threading.Thread

Класс Thread является самым элементарным из всех типов в пространстве имен

Класс System.Threading.Thread Класс Thread является самым элементарным из всех типов в пространстве
System.Threading. Он представляет объектно-ориентированную оболочку вокруг заданного пути выполнения внутри отдельного домена приложения. В этом классе определено несколько методов (статических и уровня экземпляра), которые позволяют создавать новые потоки внутри текущего домена приложения, а также приостанавливать, останавливать и уничтожать указанный поток.

Слайд 9

Статические члены Thread

Статические члены Thread

Слайд 10

Члены уровня экземпляра Thread

Члены уровня экземпляра Thread

Слайд 11

Thread. Свойство Priority

Lowest
BelowNormal
Normal
AboveNormal
Highest

Thread. Свойство Priority Lowest BelowNormal Normal AboveNormal Highest

Слайд 12

Thread. Конструкторы

Thread(ParameterizedThreadStart) - Инициализирует новый экземпляр класса Thread, при этом указывается делегат,

Thread. Конструкторы Thread(ParameterizedThreadStart) - Инициализирует новый экземпляр класса Thread, при этом указывается
позволяющий объекту быть переданным в поток при запуске потока.
Thread(ThreadStart) - Инициализация нового экземпляра класса Thread.
Thread(ParameterizedThreadStart, Int32) - Инициализирует новый экземпляр класса Thread, при этом указывается делегат, позволяющий объекту быть переданным в поток при запуске потока с указанием максимального размера стека для потока.
Thread(ThreadStart, Int32) - Инициализирует новый экземпляр класса Thread, указывая максимальный размер стека для потока.

Слайд 14

Thread. Запуск потока

Thread. Запуск потока

Слайд 15

Thread. Запуск потока с параметрами

Thread. Запуск потока с параметрами

Слайд 16

Оператор lock

Оператор lock определяет блок кода, внутри которого весь код блокируется и

Оператор lock Оператор lock определяет блок кода, внутри которого весь код блокируется
становится недоступным для других потоков до завершения работы текущего потока.
Избегайте использования следующих объектов в качестве объектов блокировки:
this, так как он может использоваться вызывающими объектами как блокировка;
экземпляров Type, так как их может получать оператор typeof или отражение;
строковых экземпляров, включая строковые литералы, так как они могут быть интернированы.

Слайд 17

Monitor

Наряду с оператором lock для синхронизации потоков мы можем использовать мониторы, представленные

Monitor Наряду с оператором lock для синхронизации потоков мы можем использовать мониторы,
классом System.Threading.Monitor. Фактически конструкция оператора lock инкапсулирует в себе синтаксис использования мониторов.

Слайд 18

Semaphore

Семафоры позволяют ограничить доступ определенным количеством объектов.
Его конструктор принимает два параметра: первый

Semaphore Семафоры позволяют ограничить доступ определенным количеством объектов. Его конструктор принимает два
указывает, какому числу объектов изначально будет доступен семафор, а второй параметр указывает, какой максимальное число объектов будет использовать данный семафор.
Потоки вводят семафор, вызывая метод WaitOne(), который наследуется от класса WaitHandle, и освобождает семафор, вызывая метод Release().
Счетчик для семафора уменьшается каждый раз, когда поток входит в семафор, и увеличивается, когда поток освобождает семафор. Если значение счетчика равно нулю, последующие запросы блокируются до освобождения семафора другими потоками. Когда семафор освобожден всеми потоками, счетчик будет иметь максимальное значение, указанное при создании семафора.
Нет гарантированного порядка, например FIFO или LIFO, в котором заблокированные потоки вводят семафор.
Локальный семафор существует только в пределах процесса. Его может использовать любой поток в вашем процессе, имеющий ссылку на локальный объект Semaphore. Каждый объект Semaphore является отдельным локальным семафором.

Слайд 19

Mutex

Mutex является классом-оболочкой над соответствующим объектом ОС Windows "мьютекс".
Когда двум или более

Mutex Mutex является классом-оболочкой над соответствующим объектом ОС Windows "мьютекс". Когда двум
потокам требуется одновременный доступ к общему ресурсу, системе необходим механизм синхронизации, гарантирующий, что ресурс будет использоваться только одним потоком в каждый момент времени. Mutex — это примитив синхронизации, предоставляющий эксклюзивный доступ к общему ресурсу только одному потоку. Если поток получает мьютекс, второй поток, желающий получить этот мьютекс, приостанавливается до тех пор, пока первый поток не освободит мьютекс.
Класс Mutex обеспечивает идентификацию потоков, поэтому мьютекс может быть освобожден только потоком, который его получил. В отличие от этого, класс Semaphore не применяет удостоверение потока. Мьютекс также может передаваться через границы домена приложения.
Основную работу по синхронизации выполняют методы WaitOne() и ReleaseMutex().

Слайд 20

Interlocked

Предоставляет атомарные операции для переменных, общедоступных нескольким потокам.
public void AddOne()
{
int newVal

Interlocked Предоставляет атомарные операции для переменных, общедоступных нескольким потокам. public void AddOne()
= Interlocked.Increment(ref intVal);
}

Слайд 21

ThreadPool

ThreadPool - Предоставляет пул потоков, который можно использовать для выполнения задач, отправки

ThreadPool ThreadPool - Предоставляет пул потоков, который можно использовать для выполнения задач,
рабочих элементов, обработки асинхронного ввода-вывода, ожидания от имени других потоков и обработки таймеров. Многие приложения создают потоки, которые тратят много времени на спящий режим, ожидая возникновения события. Другие потоки могут войти в спящее состояние только для периодического опроса на наличие изменений или сведений о состоянии обновления. Пул потоков позволяет более эффективно использовать потоки, предоставляя приложению пул рабочих потоков, управляемых системой

Слайд 23

Параллельное программирование и библиотека TPL

В эпоху многоядерных машин, которые позволяют параллельно выполнять

Параллельное программирование и библиотека TPL В эпоху многоядерных машин, которые позволяют параллельно
сразу несколько процессов, стандартных средств работы с потоками в .NET уже оказалось недостаточно. Поэтому во фреймворк .NET была добавлена библиотека параллельных задач TPL (Task Parallel Library), основной функционал которой располагается в пространстве имен System.Threading.Tasks. Данная библиотека позволяет распараллелить задачи и выполнять их сразу на нескольких процессорах, если на целевом компьютере имеется несколько ядер. Кроме того, упрощается сама работа по созданию новых потоков. Поэтому начиная с .NET 4.0. рекомендуется использовать именно TPL и ее классы для создания многопоточных приложений, хотя стандартные средства и класс Thread по-прежнему находят широкое применение.

Слайд 24

Task-based asynchronous pattern (TAP)

Task-based asynchronous pattern (TAP)

Слайд 25

async/await

Ключевыми для работы с асинхронными вызовами в C# являются два ключевых слова: async и await,

async/await Ключевыми для работы с асинхронными вызовами в C# являются два ключевых
цель которых – упростить написание асинхронного кода. Они используются вместе для создания асинхронного метода.
Асинхонный метод обладает следующими признаками:
В заголовке метода используется модификатор async
Метод содержит одно или несколько выражений await
В качестве возвращаемого типа используется один из следующих:
void
Task
Task
ValueTask

Слайд 26

Как создать и запустить задачу?

Фабрики запущенных задач. Run — более легкая версия метода StartNew

Как создать и запустить задачу? Фабрики запущенных задач. Run — более легкая
с установленными дополнительными параметрами по умолчанию. Возвращает созданную и запущенную задачу. Самый популярный способ запуска задач. Оба метода вызывают скрытый от нас Task.InternalStartNew. Возвращают объект Task.
Фабрики завершенных задач. Иногда нужно вернуть результат задачи без необходимости создавать асинхронную операцию. Это может пригодиться в случае подмены результата операции на заглушку при юнит-тестировании или при возврате заранее известного/рассчитанного результата.
Конструктор. Создает незапущенную задачу, которую вы можете далее запустить. Я не рекомендую использовать этот способ. Старайтесь использовать фабрики, если это возможно, чтобы не писать дополнительную логику по запуску.
Фабрики-таскофикаторы. Помогают либо произвести миграцию с других асинхронных моделей в TAP, либо обернуть логику ожидания результата в вашем классе в TAP. Например, FromAsync принимает методы паттерна APM в качестве аргументов и возвращает Task, который оборачивает более ранний паттерн в новый.

Слайд 27

Отмена асинхронных операций

Для отмены асинхронных операций используются классы CancellationToken и CancellationTokenSource.
CancellationToken содержит информацию о том,

Отмена асинхронных операций Для отмены асинхронных операций используются классы CancellationToken и CancellationTokenSource.
надо ли отменять асинхронную задачу. Асинхронная задача, в которую передается объект CancellationToken, периодически проверяет состояние этого объекта. Если его свойство IsCancellationRequested равно true, то задача должна остановить все свои операции.
Для создания объекта CancellationToken применяется объект CancellationTokenSource. Кроме того, при вызове у CancellationTokenSource метода Cancel() у объекта CancellationToken свойство IsCancellationRequested будет установлено в true.

Слайд 29

Как следить за прогрессом выполнения?

TAP содержит специальный интерфейс для использования в своих асинхронных классах —

Как следить за прогрессом выполнения? TAP содержит специальный интерфейс для использования в
IProgress, где T — тип, содержащий информацию о прогрессе, например int. Согласно конвенциям, IProgress может передаваться как последние аргументы в метод вместе с CancellationToken. В случае если вы хотите передать только что-то из них, в паттерне существуют значения по умолчанию: для IProgress принято передавать null, а для CancellationToken — CancellationToken.None, так как это структура.

Слайд 30

Как синхронизировать задачи?

Как синхронизировать задачи?

Слайд 31

Task.WaitAll(tasks) и Task.WaitAny(tasks)

Task.WaitAll(tasks) и Task.WaitAny(tasks)

Слайд 32

Как извлечь результат из задачи?

До появления await извлекать результат из задач можно было такими блокирующими

Как извлечь результат из задачи? До появления await извлекать результат из задач
способами:
t.Result(); — возврат результата / выброс исключения AggregateException.
t.Wait(); — ожидание выполнения задачи, выброс исключения AggregateException.
t.GetAwaiter().GetResult(); — возврат результата / выброс оригинального исключения — служебный метод компилятора, поэтому использовать его не рекомендуется. Используется механизмом async/await.
После появления async/await рекомендованной техникой стал оператор await, производящий неблокирующее ожидание. То есть если await добрался до незавершенной задачи, выполнение кода в потоке будет прервано и продолжится только с завершением задачи.
await t; — возврат результата / выброс оригинального исключения.
Следует заметить, что для t.GetAwaiter().GetResult(); и await будет выброшено только первое исключение, аналогично манере поведения обычного синхронного кода.

Слайд 33

Как запустить задачу и ожидать ее результат?

Как запустить задачу и ожидать ее результат?

Слайд 34

Как запустить задачу и ожидать ее результат?

Как запустить задачу и ожидать ее результат?

Слайд 35

Исключения

Исключения

Слайд 37

TaskCompletionSource

TaskCompletionSource

Слайд 38

Домашка

Чем отличается SemaphoreSlim от Semaphore? Когда какой выбрать?
Прочитать статью про асинхронное программирование

Домашка Чем отличается SemaphoreSlim от Semaphore? Когда какой выбрать? Прочитать статью про
(ссылка в «Что почитать»)
Задание: С использованием Thread-ов написать приложение, реализующее патерн Publisher/Subscriber. Необходимо реализовать 2 класса Publisher, который генерирует случайные целые числа и складывает их в очередь. Класс Subscriber, который опрашивает очередь и вычитывает из нее числа и выводит их в консоль. Очередь должна быть потокобезопасная. В программе запуска может быть несколько экземпляров типа Publisher, которые одновременно генерируют случайные числа и складывают их в очередь. Должен быть только один объект типа Subscriber получающий данные из очереди.
Имя файла: Многопоточность,-асинхроность.pptx
Количество просмотров: 38
Количество скачиваний: 1