- •А.А. Волосевич
- •Содержание
- •1. Работа с числами
- •2. Представление даты и времени
- •3. Работа со строками и текстом
- •4. Преобразование информации
- •5. Сравнение для выяснения равенства
- •6. Сравнение для выяснения порядка
- •7. Жизненный цикл объектов
- •7.1. Алгоритм сборки мусора
- •7.2. Финализаторы и интерфейс iDisposable
- •7.3. Слабые ссылки
- •8. Перечислители и итераторы
- •9. Стандартные интерфейсы коллекций
- •10. Массивы и класс System.Array
- •11. Типы для работы с коллекциями-списками
- •12. Типы для работы с коллекциями-множествами
- •13. Типы для работы с коллекциями-словарями
- •14. Типы для создания пользовательских коллекций
- •15. Технология linq to Objects
- •1. Оператор условия Where().
- •2. Операторы проекций.
- •3. Операторы упорядочивания.
- •4. Оператор группировки GroupBy().
- •5. Операторы соединения.
- •6. Операторы работы с множествами.
- •7. Операторы агрегирования.
- •8. Операторы генерирования.
- •9. Операторы кванторов и сравнения.
- •10. Операторы разбиения.
- •11. Операторы элемента.
- •12. Операторы преобразования.
- •16. Работа с объектами файловой системы
- •17. Ввод и вывод информации
- •17.1. Потоки данных и декораторы потоков
- •2. Классы для работы с потоками, связанными с хранилищами.
- •3. Декораторы потоков.
- •4. Адаптеры потоков.
- •17.2. Адаптеры потоков
- •18. Основы xml
- •19. Технология linq to xml
- •20. Дополнительные возможности обработки xml
- •21. Сериализация времени выполнения
- •22. Контракты данных и xml-сериализация
- •23. Состав и взаимодействие сборок
- •24. Метаданные и получение информации о типах
- •25. Позднее связывание и кодогенерация
- •26. Атрибуты
- •27. Динамическое связывание
- •28. Файлы конфигурации
- •29. Диагностика и мониторинг
- •30. Процессы и домены
- •31. Основы многопоточного программирования
- •32. Синхронизация потоков
- •32.1. Критические секции
- •32.2. Синхронизация на основе подачи сигналов
- •32.3. Неблокирующие средства синхронизации
- •32.4. Разделение данных между потоками
- •33. Библиотека параллельных задач
- •33.1. Параллелизм на уровне задач
- •33.2. Параллелизм при императивной обработке данных
- •33.3. Параллелизм при декларативной обработке данных
- •33.4. Обработка исключений и отмена выполнения задач
- •33.5. Коллекции, поддерживающие параллелизм
- •34. Асинхронный вызов методов
- •Литература
33. Библиотека параллельных задач
Библиотека параллельных задач (Task Parallel Library, TPL) является частью платформы .NET 4 и представляет собой набор типов в пространствах имён System.Threading.Tasks и System.Threading. Эта библиотека предназначена для повышения производительности разработчиков за счёт упрощения добавления параллелизма в приложения. Она динамически масштабирует степень параллелизма для наиболее эффективного использования всех доступных процессорных ядер.
TPL обеспечивает три уровня организации параллелизма:
1. Параллелизм на уровне задач. Библиотека обеспечивает высокоуровневую работу с пулом потоков, позволяя явно структурировать параллельно исполняющийся код с помощью легковесных задач. Планировщик библиотеки выполняет диспетчеризацию задач, а также предоставляет единообразный механизм отмены задач и обработки исключительных ситуаций.
2. Параллелизм при императивной обработке данных. Библиотека содержит параллельные реализации основных итеративных операторов, таких как циклы for и foreach. При этом выполнение автоматически распределяется на все процессорные ядра вычислительной системы.
3. Параллелизм при декларативной обработке данных реализуется при помощи параллельного интегрированного языка запросов (PLINQ). PLINQ выполняет запросы LINQ параллельно, обеспечивая масштабируемость и загрузку процессорных ядер.
33.1. Параллелизм на уровне задач
Параллелизм на уровне задач – базовый элемент TPL. Задача (task) – сущность, которая в целом подобна потоку. Основное различие заключается в том, что исполнением задач управляет специальный планировщик, опирающийся в своей работе на пул потоков.
Для представления задач используются классы Task и Task<T>, размещённые в пространстве имён System.Threading.Tasks. Табл. 20 содержит описание элементов класса Task.
Таблица 20
Элементы класса Task
Имя элемента |
Описание |
AsyncState |
Объект, заданный при создании задачи как аргумент Action<object> |
ContinueWith(), ContinueWith<T>() |
Используются для указания метода, выполняемого после завершения текущей задачи |
CreationOptions |
Опции, указанные при создании задачи (тип TaskCreationOptions) |
CurrentId |
Статическое свойство типа int?, которое возвращает целочисленный идентификатор текущей задачи |
Dispose() |
Освобождение ресурсов, связанных с задачей |
Exception |
Возвращает объект типа AggregateException, который соответствует исключению, прервавшему выполнение задачи |
Factory |
Доступ к фабрике, содержащей методы создания Task и Task<T> |
Id |
Целочисленный идентификатор задачи |
IsCanceled |
Булево свойство, указывающее, была ли задача отменена |
IsCompleted |
Свойство равно true, если выполнение задачи успешно завершилось |
IsFaulted |
Свойство равно true, если задача сгенерировала исключение |
RunSynchronously() |
Запуск задачи синхронно |
Start() |
Запуск задачи асинхронно |
Status |
Возвращает текущий статус задачи (объект типа TaskStatus) |
Wait() |
Приостанавливает текущий поток до завершения задачи |
WaitAll() |
Статический метод; приостанавливает текущий поток до завершения всех указанных задач |
WaitAny() |
Статический метод; приостанавливает текущий поток до завершения любой из указанных задач |
Для создания задачи используется один из перегруженных конструкторов класса Task. При этом указывается аргумент типа Action – метод, выполняемый в задаче. Если необходим метод с параметром, используется Action<object> и дополнительный аргумент типа object.
Action m1 = () => {
Thread.Sleep(2000);
Console.WriteLine("Done");
};
Action<object> m2 = obj => {
Thread.Sleep(1000);
Console.WriteLine(obj.ToString());
};
var t1 = new Task(m1);
var t2 = new Task(m2, 25);
Перегруженные конструкторы класса Task принимают опциональные аргументы типа CancellationToken и TaskCreationOptions. Перечисление TaskCreationOptions задаёт вид задачи (например, LongRunning – долгая задача). Структура CancellationToken применяется для прерывания задачи.
var t1 = new Task(m1, TaskCreationOptions.LongRunning);
Созданная задача ставится в очередь планировщика и запускается при помощи методов Start() или RunSynchronously(). Второй метод запускает задачу в текущем потоке. Оба метода могут принимать аргумент типа TaskScheduler (пользовательский планировщик задач).
// используем задачи t1 и t2, объявленные выше
t1.Start(); // асинхронный запуск
t2.RunSynchronously(); // синхронный запуск
Console.WriteLine("Tasks were started"); // напечатано через 1 сек.
Метод ContinueWith() позволяет создать цепочку задач. Этот метод принимает объект-делегат, инкапсулирующий метод продолжения. Метод ContinueWith() можно вызвать как до, так и после старта задачи.
t1.ContinueWith(task => Console.WriteLine("After task " + task.Id));
Методы Wait(), WaitAll() и WaitAny() останавливают основной поток до завершения задачи (или задач). Перегруженные версии методов позволяют задать период ожидания завершения и токен отмены.
t1.Wait(1000);
Task.WaitAll(t1, t2);
Класс Task<T> наследуется от Task и описывает задачу, возвращающую значение типа T. Дополнительно к элементам базового класса, Task<T> объявляет свойство Result для хранения вычисленного значения. Конструкторы класса Task<T> принимают аргументы типа Func<T> и Func<object, T> (опционально – аргументы типа CancellationToken и TaskCreationOptions).
Func<int> func = () => {
Thread.Sleep(2000);
return 100;
};
var task = new Task<int>(func);
Console.WriteLine(task.Status); // Created
task.Start();
Console.WriteLine(task.Status); // WaitingToRun
task.Wait();
Console.WriteLine(task.Result); // 100
Класс TaskFactory содержит набор методов, соответствующих некоторым сценариям использования задач – StartNew(), FromAsync(), ContinueWhenAll(), ContinueWhenAny(). Экземпляр TaskFactory доступен через статическое свойство Task.Factory.
Task.Factory.StartNew(() => {
Thread.Sleep(2000);
Console.WriteLine("Done");
});