1. Темы лекции: Асинхронное программирование в C#.
Практическое задание: Асинхронное программирование в C#.
Тренер: Игорь Шкулипа, к.т.н.
Платформа .Net и язык программирования C#.
Занятие 16
2. http://www.slideshare.net/IgorShkulipa 2
Асинхронное программирование
Асинхронное программирование — это набор методик для
реализации дорогостоящих операций, которые выполняются
параллельно с остальной частью программы. Одна из областей, где
часто применяется асинхронное программирование, — программы с
графическим UI: как правило, замораживать UI до завершения
дорогостоящей операции неприемлемо. Кроме того, асинхронные
операции важны для серверных приложений, которым нужно
параллельно обрабатывать множество клиентских запросов.
К типичным примерам асинхронных операций, часто наблюдаемым на
практике, относятся отправка запроса на сервер и ожидание ответа,
чтение данных с жесткого диска и выполнение ресурсоемких
вычислений вроде проверки правописания.
3. http://www.slideshare.net/IgorShkulipa 3
Библиотека параллельных задач
Библиотека параллельных задач (TPL), как и предполагает ее имя, основывается
на концепции задачи. Термин параллелизм задач означает одновременное
выполнение одной или нескольких разных задач. Задача представляет собой
асинхронную операцию и в некотором роде напоминает создание нового потока
или рабочего элемента ThreadPool, но на более высоком уровне абстракции.
Задачи предоставляют два основных преимущества.
• Более эффективное и масштабируемое использование системных ресурсов.
В фоновом режиме задачи помещаются в очередь ThreadPool,
усовершенствованный с помощью алгоритмов, которые определяют и
настраивают количество потоков, повышающих производительность. Это
делает задачи относительно простыми и позволяет создавать множество задач
для использования точного параллелизма. В дополнение к этому для
обеспечения балансировки нагрузки используются широко известные
алгоритмы переноса нагрузки.
• Больший программный контроль по сравнению с потоком или рабочим
элементом.
Задачи и построение платформы на их основе предоставляют богатый набор
интерфейсов API, которые поддерживают ожидание, отмену, продолжения,
надежную обработку исключений, подробные состояния, пользовательское
планирование и многое другое.
4. http://www.slideshare.net/IgorShkulipa 4
Тип Action<T>
public delegate void Action<in T>(T obj)
• T - тип параметра метода, инкапсулируемого данным делегатом.
Этот параметр типа является контрвариантным. Это означает, что
можно использовать либо указанный тип, либо менее производный
тип.
• obj - тип: T, Параметр метода, инкапсулируемого данным делегатом.
Делегат Action<T> можно использовать для передачи метода в качестве
параметра без явного объявления пользовательского делегата.
Инкапсулируемый метод должен соответствовать заданной этим
делегатом сигнатуре метода. Это означает, что инкапсулированный метод
должен иметь один параметр, передаваемый по значению, и не должен
возвращать значение.
5. http://www.slideshare.net/IgorShkulipa 5
Класс Task
using System.Threading.Tasks
[HostProtectionAttribute(SecurityAction.LinkDemand,
Synchronization = true,
ExternalThreading = true)]
public class Task : IAsyncResult, IDisposable
Представляет асинхронную операцию.
Task(Action) Инициализирует новую задачу Task с заданным действием.
Task(Action,
CancellationToken)
Инициализирует новую задачу Task с заданными действием и токеном
CancellationToken.
Task(Action,
TaskCreationOptions)
Инициализирует новую задачу Task с заданными действием и
параметрами создания.
Task(Action<Object>, Object)
Инициализирует новую задачу Task с заданными действием и
состоянием.
Task(Action, CancellationToken,
TaskCreationOptions)
Инициализирует новую задачу Task с заданными действием и
параметрами создания.
Task(Action<Object>, Object,
CancellationToken)
Инициализирует новую задачу Task с заданными действием, состоянием
и параметрами.
Task(Action<Object>, Object,
TaskCreationOptions)
Инициализирует новую задачу Task с заданными действием, состоянием
и параметрами.
Task(Action<Object>, Object,
CancellationToken,
TaskCreationOptions)
Инициализирует новую задачу Task с заданными действием, состоянием
и параметрами.
6. http://www.slideshare.net/IgorShkulipa 6
Task. Свойства
AsyncState
Возвращает объект состояния, предоставленный при создании
задачи Task, или значение NULL, если объект не предоставлен.
CreationOptions
Возвращает объект TaskCreationOptions, использованный при
создании данной задачи.
CurrentId
Возвращает уникальный идентификатор выполняющейся в
настоящее время задачи Task.
Exception
Возвращает объект AggregateException, который привел к
преждевременному завершению задачи Task. Если Task
завершенные успешно или пока не бросало исключений, это
значение null.
Factory
Предоставляет доступ к методам фабрики для создания
экземпляров Task и Task<TResult>.
Id
Возвращает уникальный идентификатор данного экземпляра
Task.
IsCanceled
Возвращает значение, указывающее, завершилось ли
выполнение данного экземпляра Task из-за отмены.
IsCompleted
Возвращает значение, которое показывает, завершилась ли
задача Task.
IsFaulted
Возвращает значение, указывающее, завершилась ли задача
Task из-за необработанного исключения.
Status Возвращает состояние TaskStatus данной задачи.
8. http://www.slideshare.net/IgorShkulipa 8
Класс Parallel
Предоставляет поддержку параллельных циклов и областей.
[HostProtectionAttribute(SecurityAction.LinkDemand,
Synchronization = true,
ExternalThreading = true)]
public static class Parallel;
Методы:
• For + 10 перегрузок – выполняет цикл for с заданными аргументами
• ForEach + 19 перегрузок – выполняет цикл foreach с заданными
аргументами
• Invoke - выполняет все предоставленные действия, в том числе
параллельно.
10. http://www.slideshare.net/IgorShkulipa 10
Пример. Вычисление 10000 факториалов.
Последовательная версия.
using System.Numerics;
class Program
{
static void Main(string[] args)
{
BigInteger FactorialsCount = 2000;
var Results = new Dictionary<BigInteger, BigInteger>();
Func<BigInteger, BigInteger> factorial = null;
factorial = (n) => (n == 0) ? 1 : n * factorial(n - 1);
for (BigInteger i = 0; i < FactorialsCount; i++)
{
Results.Add(i, factorial(i));
}
foreach (var item in Results)
{
Console.WriteLine("N={0}, Factorial={1}",
item.Key, item.Value);
}
Console.ReadKey();
}
}
11. http://www.slideshare.net/IgorShkulipa 11
Пример. Вычисление 10000 факториалов.
Parallel версия.
using System.Numerics;
using System.Collections.Concurrent;
class Program
{
static void Main(string[] args)
{
int FactorialsCount = 10000;
var Results =
new ConcurrentDictionary<BigInteger, BigInteger>(4, FactorialsCount);
Func<int, BigInteger> factorial = null;
factorial = (n) =>
(n == 0) ? 1 : n * factorial(n - 1);
Parallel.For(0, FactorialsCount,
(i) =>
{
Results[i] = factorial(i);
});
foreach (var item in Results)
{
Console.WriteLine("N={0}, Factorial={1}",
item.Key, item.Value);
}
Console.ReadKey();
}
}
12. http://www.slideshare.net/IgorShkulipa 12
Пример. Вычисление 10000 факториалов.
4-Parallel версия.
using System.Numerics;
using System.Collections.Concurrent;
class Program
{
static void Main(string[] args)
{
int FactorialsCount = 10000;
var Results =
new ConcurrentDictionary<BigInteger, BigInteger>(4, FactorialsCount);
Func<int, BigInteger> factorial = null;
factorial = (n) =>
(n == 0) ? 1 : n * factorial(n - 1);
for (int j = 0; j < 4; j++)
{
Parallel.For(j * 2500, (j + 1) * 2500,
(i) =>
{
Results[i] = factorial(i);
});
}
foreach (var item in Results)
{
Console.WriteLine("N={0}, Factorial={1}",
item.Key, item.Value);
}
Console.ReadKey();
}
}
13. http://www.slideshare.net/IgorShkulipa 13
Ключевое слово async
Модификатор async указывает, что модифицируемые им метод, лямбда-
выражение, или анонимный метод являются асинхронными.
Асинронный метод может возвращать значение следующих типов: Task,
Task<TResult> или void. Асинхронный метод не может принимать в
качестве своих аргументов параметры с модификаторами ref или out,
но, при этом, он может вызывать методы, имеющие такие параметры.
Указывайте Task<TResult> в качестве типа значения, возвращаемого
асинхронным методом, в том случае, если оператор return этого
метода возвращает операнд типа TResult. Если же асинхронный метод
при своём завершении не возвращает имеющего смысл значения,
используйте тип Task.
14. http://www.slideshare.net/IgorShkulipa 14
Оператор await
Оператор await применяется к задаче в асинхронных методах, для того,
чтобы приостановить выполнение метода до тех пор, пока задача не
завершится. Задача представляет собой выполняющихся работы.
Асинхронный метод, в котором используется await должен быть помечен
модификатором async. Такой метод, определенный с помощью
модификатора async, и обычно содержащий один или несколько
выражений await, называется асинхронным методом.
15. http://www.slideshare.net/IgorShkulipa 15
Пример async и await
public class AsyncClassExample
{
public async Task<string> AsyncExample()
{
await Task.Delay(5000);
return "Async Method Finished";
}
}
class Program
{
static void Main(string[] args)
{
AsyncClassExample ace = new AsyncClassExample();
Task<string> t1 = ace.AsyncExample();
string result = t1.Result;
Console.WriteLine(result);
Console.ReadKey();
}
}
Async Method Finished
16. http://www.slideshare.net/IgorShkulipa 16
Пример. Вычисление факториала 1000
public class AsyncFactorialClass {
public async Task<BigInteger> Factorial(BigInteger n) {
BigInteger result=0;
if (n == 0) return 1;
else
{
Task<BigInteger> t = Factorial(n - 1);
await t;
result = t.Result*n;
}
return result;
}
}
class Program {
static void Main(string[] args) {
AsyncFactorialClass ace = new AsyncFactorialClass();
Task<BigInteger> t1 = ace.Factorial(1000);
BigInteger result = t1.Result;
Console.WriteLine(result);
Console.ReadKey();
}
}
18. http://www.slideshare.net/IgorShkulipa 18
Лабораторная работа №16. Асинхронное
программирование в C#
В индивидуальных курсовых проектах при необходимости использовать
асинхронное программирование с помощью классов Task или Parallel, а
так же асинхронные методы с модификатором async и оператором
await.