Luxoft async.net
-
Upload
sergey-teplyakov -
Category
Documents
-
view
641 -
download
2
description
Transcript of Luxoft async.net
![Page 1: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/1.jpg)
Асинхронное программирование в .NetСергей Тепляков[email protected]
![Page 2: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/2.jpg)
О Вашем инструкторе
Сергей Тепляков Visual C# MVP, RSDN Team
member [email protected] SergeyTeplyakov.blogspot.com
1-2
![Page 3: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/3.jpg)
Цели курса…
Достоинства и недостатки синхронного программирования
Существующие паттерны асинхронного программирования на платформе .Net
Использование библиотеки PowerThreading
Использование библиотеки TPL Новые возможности C# 5
Слушатели изучат:
1-3
![Page 4: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/4.jpg)
Необходимая подготовка
Быть знакомы с основами языка C# и платформы .Net
Обладать базовыми знаниями многопоточности
Слушатели должны:
1-4
![Page 5: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/5.jpg)
Roadmap
Модель синхронного программирования
Паттерны асинхронного программирования на платформе .Net
Недостатки существующих моделей
Библиотека PowerThreading Библиотека TPL C# 5.0: async и await 1-5
![Page 6: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/6.jpg)
Недостатки синхронного программирования
Плохая масштабируемость Блокирование пользовательского
интерфейса Низкая эффективность операций
ввода/вывода Невозможность использования в
некоторых контекстах (например, с JavaScript и Silverlight)
![Page 7: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/7.jpg)
Плохая масштабируемость. последовательное выполнение
sd Sync
Client HttpWebRequest
webRequest1.GetWebResponce()
ProcessWebResponce1()
webRequest2.GetWebResponce()
ProcessWebResponce2()
![Page 8: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/8.jpg)
Плохая масштабируемость
Неэффективное использование мощностей современных многоядерных процессоров для CPU-Bound операций
Неэффективное выполнение IO-Bound операций даже для одноядерных процессоров
![Page 9: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/9.jpg)
Блокировка пользовательского интерфейса
![Page 10: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/10.jpg)
Блокировка пользовательского интерфейса
// Обработчик кнопки получения данных от веб-страницprivate void receiveDataButton_Click(object sender, EventArgs e){ Stopwatch sw = Stopwatch.StartNew(); // 1 _summaryContentLength = 0; // 2 foreach (var url in urls) { // GetResponse возвращает результат синхронно using (WebResponse webResponse = GetResponse(url)) // 3 { ProcessResponse(webResponse); // 4 executionTimeTextBox.Text = sw.ElapsedMilliseconds.ToString(); } }}
![Page 11: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/11.jpg)
А ведь это и не всегда возможно!
Некоторые среды, такие как Silverlight и JavaScript не поддерживают синхронные операции
![Page 12: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/12.jpg)
Рассматриваемые темы
Модель синхронного программирования
Паттерны асинхронного программирования на платформе .Net
Недостатки существующих моделей
Библиотека PowerThreading Библиотека TPL C# 5.0: async и await
![Page 13: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/13.jpg)
Асинхронная модель программирования
Два паттерна асинхронного программирования Classical Async Pattern Event-Based Async Pattern
![Page 14: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/14.jpg)
Classical Async Pattern
Структура паттерна:// Синхронный метод public <return> Operation(<parameters>, <out params> )
// Методы классического асинхронного паттернаpublic IAsyncResult BeginOperation(<parameters>, AsyncCallback callback, object state)public <return> EndOperation(IAsyncResult asyncResult, <out paramss>)
Пример:public WebResponse GetWebResponse(string url, out TimeSpan duration);public IAsyncResult BeginGetWebResponse(string ulr, object state);public WebResponse EndGetWebResponse(IAsyncResult ar, out TimeSpan duration);
![Page 15: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/15.jpg)
Classical Async Pattern
Метод BeginXXX инициирует асинхронную операцию
Метод BeginXXX возвращает IAsyncResult, который является маркером асинхронной операции
AsyncCallback представляет собой функцию, которая будет вызвана при завершении операции
State представляет собой любой пользовательский объект
![Page 16: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/16.jpg)
Classical Async Pattern
Все by-value и by-ref параметры синхронного метода становятся by-value параметрами BeginXXX метода
Тип возвращаемого значения синхронного метода совпадает с типом возвращаемого значения EndXXX метода
ref и out параметры синхронного метода добавляются в EndXXX метод
Исключения, генерируемые синхронным методом, генерируются методом EndXXX
![Page 17: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/17.jpg)
Примеры Classical Async Pattern
Класс System.IO.Streampublic int Read(byte[] buffer, int offset, int count)public IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)public int EndRead(IAsyncResult asyncResult)
Класс System.Net.WebRequestpublic WebResponse GetWebResponse();public IAsyncResult BeginGetWebResponse(AsyncCallback callback, object state);public WebResponse EndGetResponse(IAsyncResult asyncResult);
![Page 18: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/18.jpg)
Асинхронное выполнение sd ClassicAsync
Client HttpWebRequest IO completionForm
webRequest1.BeginGetResponse()
webRequest2.BeginGetResponse()
webRequest2.ProcessResponse()
ProcessResponse()
UpdateUIElements()
webRequest1.ProcessResponse()
ProcessResponse()
UpdateUIElements()
![Page 19: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/19.jpg)
Classical Async Pattern
В обработчике UI события: Проинициализировать дополнительные поля (теперь
без них не обойтись) Сделать неактивной кнопку В цикле начать все операции асинхронно (вызывать
метод BeginGetResponse)
![Page 20: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/20.jpg)
Classical Async Pattern
В обработчике завершения асинхронной операции: Получить WebResponse (вызывать метод
EndGetReponse) Обработать ответ, не забывая, что обработка
происходит не в потоке UI Понять, что все асинхронные операции завершены
(??) (посчитать количество завершенных операций) Сделать активной кнопку, если все операции таки
завершены Если перед началом выполнения асинхронных
операций были выделены ресурсы, то освободить их вручную
![Page 21: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/21.jpg)
Разница синхронного и асинхронного вариантов для трех веб-узлов
Среднее выполнение синхронного варианта: 520мс
Среднее выполнение асинхронного варианта: 280 мс
Количество строк кода в синхронном решении: 20
Количество строк кода в асинхронном решении: 78
![Page 22: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/22.jpg)
Event-Based Async Pattern
![Page 23: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/23.jpg)
Event-Based Async Pattern
class Class Model
AsyncCompletedEv entArgs
+ Canceled: bool+ Error: Exception+ UserState: object
Находится в пространстве имен: System.ComponentModel
MethodResult
MethodCompletedEv entArgs
+ Arg1: int+ Arg2: string+ Result: MethodResult
SomeType
+ event MethodCompleted+ event ProgressChanged
+ CancelMethod() : void+ MethodAsync(string, int) : void
Событие MethodCompleted вызывается как при успешном, так и при неудачном завершенииметода.
Метод CancelMethod и событие ProgressChanged являются опциональными.
Uses
Uses
![Page 24: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/24.jpg)
Event-Based Async Pattern
MethodAsync инициирует асинхронную операцию
Есть только одно событие MethodCompleted, EventArgs которого содержат Result, Error, IsCanceled
Возможна, но не обязательна, поддержка отмены и прогресса выполнения
![Page 25: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/25.jpg)
Event-Based Async Pattern
By-value и ref параметры синхронного метода являются входными параметрами метода MethodAsync
Ref и out-параметры становятся readonly полями MethodCompletedEventArgs
Событие MethodCompleted вызывается в «правильном» потоке (в потоке UI для WinForms или WPF)
![Page 26: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/26.jpg)
Event-Based Async Pattern
// Функция обработки принятых данныхprivate void receiveDataButton_Click(object sender, EventArgs e){ // Подготовка операции (отключение кнопки «Принять», // инициализация счетчиков и т.д. foreach (var url in urls) { var webClient = new WebClient(); webClient.DownloadDataAsync(new Uri(url)); webClient.DownloadDataCompleted += (s, ev) => { // Для обработки ошибки в этом случае нужно // обратиться к ствойству ev.Error. // Обработка результатов }; }}
![Page 27: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/27.jpg)
Да как же между ними выбрать?
Классический паттерн более низкоуровневый и более гибкий
Event-Based паттерн более простой в применении, в частности с UI дизайнерами
Классический паттерн – для кода общего назначения, Event-Based – для компонентов
Не применяйте оба паттерна для одного класса
![Page 28: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/28.jpg)
Рассматриваемые темы
Модель синхронного программирования
Паттерны асинхронного программирования на платформе .Net
Недостатки существующих моделей
Библиотека PowerThreading Библиотека TPL C# 5.0: async и await
![Page 29: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/29.jpg)
Недостатки моделейасинхронного программирования
Непонятный поток исполнения (Control Flow)
Сложность чтения кода и его сопровождения
Сложность обработки ошибок Невозможность использования
привычных языковых конструкций (using, try/finally etc)
![Page 30: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/30.jpg)
Рассматриваемые темы
Модель синхронного программирования
Паттерны асинхронного программирования на платформе .Net
Недостатки существующих моделей
Библиотека PowerThreading Библиотека TPL C# 5.0: async и await
![Page 31: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/31.jpg)
PowerThreading Library
Разработана Джеффри Рихтер и компанией Wintellect
Содержит класс AsyncEnumerator для упрощения работы с асинхронными операциями
Содержит вспомогательные классы для работы с многопоточностью (ResourceLock, ReaderWriterGate etc)
Другие вспомогательные классы (Disposer, Exception<T>, Singleton etc)
![Page 32: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/32.jpg)
Класс AsyncEnumerator.Основные концепции
Поддерживает гибкое управление асинхронными операциями (отмену, таймауты и т.п.)
Использует преимущество блока итераторов (Iterator block) для упрощения потока исполнения
Использует SynchronizationContext для маршалинга потока выполнения в поток UI
![Page 33: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/33.jpg)
Класс AsyncEnumerator.Простой пример
static IEnumerator<int> WorkerMethod(){ // Инициируем n асинхронных операций, // вызываем BeginRead, BeginGetWebResponse, BeginExecuteCommand etc // "возвращаем" n, что говорит AsyncEnumerator-у // о количестве запущенных асинхронных операций yield return n; // класс AsyncEnumerator вызовет в следующий раз // метод MoveNext нашего енумератора (и мы здесь получим управление) // только после завершения указанного количества асинхронных операций. // Причем, если экземпляр класса AsyncEnumerator-а создавался // с контекстом синхронизации (например, он создавался в потоке UI) // то метод MoveNext будет вызван в потоке UI! // Начинаем еще несколько асинхронных операций (например, k) yield return k; } // Создаем экземпляр енумератораAsyncEnumerator ae = new AsyncEnumerator();// Запускаем асинхронные операции, всю грязную работу// берет на себя AsyncEnumeratorae.BeginExecute(WorkerMethod(), ae.EndExecute);
![Page 34: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/34.jpg)
Отступление от темы. Блоки итераторов
static IEnumerator<int> GetNumbers(){ string padding = "\t\t"; Console.WriteLine(padding + "Первая строка метода GetNumbers()"); Console.WriteLine(padding + "Сразу перед yield return 7"); yield return 7; Console.WriteLine(padding + "Сразу после yield return 7"); Console.WriteLine(padding + "Сразу перед yield return 42"); yield return 42; Console.WriteLine(padding + "Сразу после yield return 42");}
![Page 35: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/35.jpg)
Визуализация итераторов
static IEnumerator<int> GetNumbers(){ string padding = "\t\t"; Console.WriteLine(padding + "Первая строка метода GetNumbers()"); // 1 Console.WriteLine(padding + "Сразу перед yield return 7"); // 2 yield return 7; // 3 Console.WriteLine(padding + "Сразу после yield return 7"); // 4 Console.WriteLine(padding + "Сразу перед yield return 42"); // 5 yield return 42; // 6 Console.WriteLine(padding + "Сразу после yield return 42"); //7}
WriteLine("Вызываем GetNumbers()");IEnumerator<int> iterator = GetNumbers();
WriteLine("Вызываем MoveNext()...");bool more = iterator.MoveNext();WriteLine("Result=...", iterator.Current);
WriteLine("Снова вызываем MoveNext()...");more = iterator.MoveNext();WriteLine("Result=...", iterator.Current);
WriteLine("Снова вызываем MoveNext()...");more = iterator.MoveNext();WriteLine("Result={0} (stopping)", more);
Результат:Вызываем GetNumbers()
![Page 36: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/36.jpg)
Визуализация итераторов
static IEnumerator<int> GetNumbers(){ string padding = "\t\t"; Console.WriteLine(padding + "Первая строка метода GetNumbers()"); Console.WriteLine(padding + "Сразу перед yield return 7"); yield return 7; Console.WriteLine(padding + "Сразу после yield return 7"); Console.WriteLine(padding + "Сразу перед yield return 42"); yield return 42; // 6 Console.WriteLine(padding + "Сразу после yield return 42"); }
WriteLine("Вызываем GetNumbers()");IEnumerator<int> iterator = GetNumbers();
WriteLine("Вызываем MoveNext()...");bool more = iterator.MoveNext();WriteLine("Result=...", iterator.Current);
WriteLine("Снова вызываем MoveNext()...");more = iterator.MoveNext();WriteLine("Result=...", iterator.Current);
WriteLine("Снова вызываем MoveNext()...");more = iterator.MoveNext();WriteLine("Result={0} (stopping)", more);
Результат:Вызываем GetNumbers() Вызываем MoveNext()... Первая строка метода GetNumbers() Сразу перед yield return 7 Result=True; Current=7
![Page 37: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/37.jpg)
Визуализация итераторов
static IEnumerator<int> GetNumbers(){ string padding = "\t\t"; Console.WriteLine(padding + "Первая строка метода GetNumbers()"); Console.WriteLine(padding + "Сразу перед yield return 7"); yield return 7; Console.WriteLine(padding + "Сразу после yield return 7"); Console.WriteLine(padding + "Сразу перед yield return 42");
yield return 42; Console.WriteLine(padding + "Сразу после yield return 42");}
WriteLine("Вызываем GetNumbers()");IEnumerator<int> iterator = GetNumbers();
WriteLine("Вызываем MoveNext()...");bool more = iterator.MoveNext();WriteLine("Result=...", iterator.Current);
WriteLine("Снова вызываем MoveNext()...");more = iterator.MoveNext();WriteLine("Result=...“, iterator.Current);
WriteLine("Снова вызываем MoveNext()...");more = iterator.MoveNext();WriteLine("Result={0} (stopping)", more);
Результат:Вызываем GetNumbers() Вызываем MoveNext()... Первая строка метода GetNumbers() Сразу перед yield return 7 Result=True; Current=7 Снова вызываем MoveNext()... Сразу после yield return 7 Сразу перед yield return 42 Result=True; Current=42
![Page 38: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/38.jpg)
Визуализация итераторов
static IEnumerator<int> GetNumbers(){ string padding = "\t\t"; Console.WriteLine(padding + "Первая строка метода GetNumbers()"); Console.WriteLine(padding + "Сразу перед yield return 7"); yield return 7; Console.WriteLine(padding + "Сразу после yield return 7"); Console.WriteLine(padding + "Сразу перед yield return 42"); yield return 42; Console.WriteLine(padding + "Сразу после yield return 42");}
WriteLine("Вызываем GetNumbers()");IEnumerator<int> iterator = GetNumbers();
WriteLine("Вызываем MoveNext()...");bool more = iterator.MoveNext();WriteLine("Result=...", iterator.Current);
WriteLine("Снова вызываем MoveNext()...");more = iterator.MoveNext();WriteLine("Result=...", iterator.Current);
WriteLine("Снова вызываем MoveNext()...");more = iterator.MoveNext();WriteLine("Result={0} (stopping)", more);
Результат:Вызываем GetNumbers() Вызываем MoveNext()... Первая строка метода GetNumbers() Сразу перед yield return 7 Result=True; Current=7 Снова вызываем MoveNext()... Сразу после yield return 7 Сразу перед yield return 42 Result=True; Current=42 Result=False (stopping)
![Page 39: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/39.jpg)
AsyncEnumerator. Участники
Класс AsyncEnumerator Рабочий метод, возвращающий
IEnumerator<int> Кто-то, связывающий все это
воедино
![Page 40: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/40.jpg)
AsyncEnumerator sd AsyncEnumerator
AsyncEnumerator WorkerMethod WebRequest IO Completion
В качестве метода обработки завершения асинхронной операции передается метод класса AsyncEnumerator-а.
Теперь рабочий метод (WorkerMethod) может обработать завершенные операции и начать новые асинхронные операции.
Первый вызов MoveNext енумератора инициирует асинхронные операции.
calling to MoveNext()
webRequest1.BeginGetResponse()
webRequest2.BeginGetResponse()
WebRequest2Complete()
WebRequest1Complete()
calling toMoveNext()
![Page 41: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/41.jpg)
Пример использования класса AsyncEnumerator
private IEnumerator<int> GetWebData(AsyncEnumerator enumerator){ // Начинаем несколько асинхронных операций WebRequest webRequest1 = WebRequest.Create(url1); webRequest1.BeginGetResponse(enumerator.End(), null);
WebRequest webRequest2 = WebRequest.Create(url2); webRequest2.BeginGetResponse(enumerator.End(), null);
yield return 2; // 2 - это количество асинхронных операций
// Сюда мы попадем уже тогда, когда все асинхронные операции завершены WebResponse webResponse1 = webRequest1.EndGetResponse(enumerator.DequeueAsyncResult()); WebResponse webResponse2 = webRequest2.EndGetResponse(enumerator.DequeueAsyncResult());
// Обрабатываем полученные результаты аналогичным образом}
![Page 42: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/42.jpg)
Пример использования класса AsyncEnumerator
private void receiveDataButton_Click(object sender, EventArgs e){ asyncEnumerator = new AsyncEnumerator(); // AsyncEnumerator автоматически запоминает контекст синхронизации // Запускаем процесс получения данных асинхронно asyncEnumerator.BeginExecute(GetWebData(asyncEnumerator), asyncEnumerator.EndExecute);}
![Page 43: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/43.jpg)
Рассматриваемые темы
Модель синхронного программирования
Паттерны асинхронного программирования на платформе .Net
Недостатки существующих моделей
Библиотека PowerThreading Библиотека TPL C# 5.0: async и await
![Page 44: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/44.jpg)
Библиотека TPL
Параллелизм задач Класс Parallel (Parallel.ForEach
etc) Parallel LINQ (a.k.a. PLINQ)
![Page 45: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/45.jpg)
Ключевые классы
Task – инкапсулирует единицу работы Task<TResult> - единица работы с
определенным типом результата TaskFactory, TaskFactory<TResult> – фабрики
создания задач TaskScheduler – управляет «расписанием»
запуска задач TaskCompletionSource – управляет «временем
жизни» задачи
![Page 46: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/46.jpg)
Класс Task<T>
Представляет собой «незавершенную операцию» или «единицу работы»
Это может быть операция ввода/вывода, операция в фоновом потоке, в выделенном потоке и т.д.
Поддерживает «продолжения» с помощью ContinueWith
var task2 = task1.ContinueWith(t => … t.Result …);
Содержит ряд вспомогательных методов: WhenAll, WhenAny etc
![Page 47: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/47.jpg)
Примеры использования
1. Простая задачаTask.Factory.StartNew(() => Console.WriteLine("Hello from a task!"));
2. Запуск задачи в выделенном потокеTask task = Task.Factory.StartNew( () => {
Console.WriteLine("Выполняем длительную операцию"); Thread.Sleep(TimeSpan.FromHours(1)); Console.WriteLine("Длительная операция завершена");
}, TaskCreationOptions.LongRunning);
![Page 48: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/48.jpg)
Примеры использования
3. Получение данных от веб-узлаTask<long> task = new Task<long>(() => { var webRequest = WebRequest.Create(url); using (var webResponse = webRequest.GetResponse()) { return webResponse.ContentLength; } });task.Start();task.Wait();long result = task.Result;4. Использование классического асинхронного APIvar webRequest = WebRequest.Create(url);Task<WebResponse> task = Task<WebResponse>.Factory.FromAsync( webRequest.BeginGetResponse, webRequest.EndGetResponse, null);task.Wait();var response = task.Result;
![Page 49: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/49.jpg)
Продолжения
Task task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("\tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("\t\tTask3...")); // Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены");
![Page 50: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/50.jpg)
Продолжения
Task task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("\tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("\t\tTask3...")); // Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены");
Вывод:(ничего не происходит, поскольку задача еще не запущена)
![Page 51: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/51.jpg)
Продолжения
Task task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("\tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("\t\tTask3...")); // Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены");
Вывод:(все еще ничего не происходит, поскольку первая задача не запущена)(первой задаче установлена вторая задача в виде продолжения)
![Page 52: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/52.jpg)
Продолжения
Task task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("\tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("\t\tTask3...")); // Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены");
Вывод:(все еще ничего не происходит, поскольку первая задача не запущена)(Связке первых двух задач установлена третья задача в виде продолжения)
![Page 53: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/53.jpg)
Продолжения
Task task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("\tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("\t\tTask3...")); // Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены");
Вывод:Запускаем первую задачу
![Page 54: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/54.jpg)
Продолжения
Task task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("\tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("\t\tTask3...")); // Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены");
Вывод:Запускаем первую задачу
Ожидаем завершения цепочки задач
![Page 55: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/55.jpg)
Продолжения
Task task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("\tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("\t\tTask3...")); // Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены");
Вывод:(Выполняется первая задача)Запускаем первую задачуОжидаем завершения цепочки задач
Task1...
![Page 56: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/56.jpg)
Продолжения
Task task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("\tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("\t\tTask3...")); // Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены");
Вывод:(Выполняется вторая задача, поскольку первая уже завершилась)Запускаем первую задачуОжидаем завершения цепочки задачTask1...
Task2...
![Page 57: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/57.jpg)
Продолжения
Task task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("\tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("\t\tTask3...")); // Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены");
Вывод:(Выполняется третья задача, поскольку первая и вторая уже завершились)Запускаем первую задачуОжидаем завершения цепочки задачTask1... Task2...
Task3...
![Page 58: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/58.jpg)
Продолжения
Task task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("\tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("\t\tTask3...")); // Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены");
Вывод:(Выполняется третья задача, поскольку первая и вторая уже завершились)Запускаем первую задачуОжидаем завершения цепочки задачTask1... Task2... Task3...
Все задачи завершены
![Page 59: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/59.jpg)
Рассматриваемые темы
Модель синхронного программирования
Паттерны асинхронного программирования на платформе .Net
Недостатки существующих моделей
Библиотека PowerThreading Библиотека TPL C# 5.0: async и await
![Page 60: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/60.jpg)
Модель асинхронного программирования в C# 5
Аналогична синхронной модели Построена по тому же принципу,
что и класс AsyncEnumerator Использует Task<T> для
асинхронных операций Никто не знает, когда выйдет C#
5 Сейчас доступно Async CTP
(Community Technology Preview)
![Page 61: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/61.jpg)
Модель асинхронного программирования в C# 5
Два новых ключевых слова: async – указывает, что метод или
лямбда-выражение является асинхронным
await – является аналогом yield return и возвращает сразу же управление вызывающему коду до тех пор, пока асинхронная операция не будет завершена
![Page 62: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/62.jpg)
Модель асинхронного программирования в C# 5
static async Task<long> GetWebResponseContentLength(string url){ var webRequest = WebRequest.Create(url); Console.WriteLine("Перед вызовом await-a. Thread Id: {0}", Thread.CurrentThread.ManagedThreadId); // Начинаем асинхронную операцию Task<WebResponse> responseTask = webRequest.GetResponseAsync();
// Ожидаем получения ответа WebResponse webResponse = await responseTask; Console.WriteLine("После завершения await-а. Thread Id: {0}", Thread.CurrentThread.ManagedThreadId); // В этой строке мы уже получили ответ от веб-узла // можем обрабатывать результаты. Тип возвращаемого значения // должен соответствовать обобщенному параметру класса Task return webResponse.ContentLength;}
![Page 63: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/63.jpg)
Работа простого метода
static async Task<long> GetWebResponseContentLength(string url){ var webRequest = WebRequest.Create(url); WriteLine("Перед вызовом await-a. Thread Id: {0}"); // Начинаем асинхронную операцию Task<WebResponse> respTsk = webRequest.GetResponseAsync();
// Ожидаем получения ответа WebResponse webResponse = await respTsk; WriteLine("После завершения await-а. Thread Id: {0}");
return webResponse.ContentLength;}
WriteLine("Начало исполнения. Thread Id: {0}");
Task<long> task = GetWebResponseContentLength(url); // ожидаем завершения асинхронной операцииtask.Wait(); WriteLine("ContentLength: {0}, Thread Id: {1}");
Результаты:Начало исполнения. Thread Id: 10
Перед вызовом await-a. Thread Id: 10(Асинхронная операция запущена)
![Page 64: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/64.jpg)
Работа простого метода
static async Task<long> GetWebResponseContentLength(string url){ var webRequest = WebRequest.Create(url); WriteLine("Перед вызовом await-a. Thread Id: {0}"); // Начинаем асинхронную операцию Task<WebResponse> respTsk = webRequest.GetResponseAsync();
// Ожидаем получения ответа WebResponse webResponse = await respTsk; WriteLine("После завершения await-а. Thread Id: {0}"); return webResponse.ContentLength;}
WriteLine("Начало исполнения. Thread Id: {0}");
Task<long> task = GetWebResponseContentLength(url); // ожидаем завершения асинхронной операцииtask.Wait(); WriteLine("ContentLength: {0}, Thread Id: {1}");
Результаты:Начало исполнения. Thread Id: 10Перед вызовом await-a. Thread Id: 10
После завершения await-a. Thread Id: 14 (Эта строка выполнится только после завершения операции)
![Page 65: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/65.jpg)
Работа простого метода
static async Task<long> GetWebResponseContentLength(string url){ var webRequest = WebRequest.Create(url); WriteLine("Перед вызовом await-a. Thread Id: {0}"); // Начинаем асинхронную операцию Task<WebResponse> respTsk = webRequest.GetResponseAsync();
// Ожидаем получения ответа WebResponse webResponse = await respTsk; WriteLine("После завершения await-а. Thread Id: {0}"); return webResponse.ContentLength;}
WriteLine("Начало исполнения. Thread Id: {0}");
Task<long> task = GetWebResponseContentLength(url); // ожидаем завершения асинхронной операцииtask.Wait(); WriteLine("ContentLength:{0},Thread Id: {1}");
Результаты:Начало исполнения. Thread Id: 10Перед вызовом await-a. Thread Id: 10После завершения await-a. Thread Id: 14
ContentLength: 1672, Thread Id: 10
![Page 66: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/66.jpg)
IEnumerator<T> -> async Task<T>
yield return n -> await task
Сравнение с AsyncEnumerator
![Page 67: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/67.jpg)
Модель асинхронного программирования в C# 5
Асинхронный метод может возвращать void – для асинхронных операций
типа “fire and forget” Task – вызывающий код может
дождаться завершения асинхронной операции, которая не возвращает значения
Task<T> - для асинхронной операции, возвращающей T (string для Task<string> etc)
![Page 68: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/68.jpg)
Модель асинхронного программирования C# 5
private async void receiveDataButton_Click(object sender, EventArgs e){ Stopwatch sw = Stopwatch.StartNew(); receiveDataButton.Enabled = false; IEnumerable<Task<WebResponse>> tasks = from url in urls let webRequest = WebRequest.Create(url) select webRequest.GetResponseAsync(); // Начинаем выполнять все задачи WebResponse[] webResponses = await TaskEx.WhenAll(tasks); // Теперь мы можем обработать результаты long summaryContentLength = webResponses.Sum(s => s.ContentLength);
executionTimeTextBox.Text = sw.ElapsedMilliseconds.ToString(); summaryContentLengthTextBox.Text = summaryContentLength.ToString(); receiveDataButton.Enabled = true; foreach(var wr in webResponses) wr.Close();}
![Page 69: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/69.jpg)
Преимущества новой асинхронной модели
Простота использования Привычный поток исполнения Простота обработки ошибок и
возможность использования конструкций using, try/finally etc
try { WebResponse[] data = await TaskEx.WhenAll(tasks); // Обработка данных}catch (WebException we) { //Обработка ошибки получения данных }
![Page 70: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/70.jpg)
Преимущества новойасинхронной модели
Построена на основе проверенных идиом (Iterator blocks, AsyncEnumerator, Reactive Extensions)
Построена на основе TPL (преимущества от ее использования можно закладывать уже сейчас)
![Page 71: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/71.jpg)
Что мы изучили?
Модель синхронного программирования
Паттерны асинхронного программирования на платформе .Net
Недостатки существующих моделей
Библиотека PowerThreading Библиотека TPL C# 5.0: async и await
![Page 72: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/72.jpg)
Дополнительные ссылки
Visual Studio Asynchronous Programming (http://msdn.microsoft.com/en-us/vstudio/async.aspx)
Асинхронные операции и AsyncEnumerator (http://sergeyteplyakov.blogspot.com/2010/10/asyncenumerator.html)
«Реактивные расширения и асинхронные операции (http://sergeyteplyakov.blogspot.com/2010/11/blog-post.html)
Знакомство с асинхронными операциями в C# 5 (http://sergeyteplyakov.blogspot.com/2010/12/c-5.html)
Джефри Рихтер. Упрощение модели асинхронного программирования с помощью AsyncEnumerator (http://msdn.microsoft.com/ru-ru/magazine/cc546608.aspx)
Джеффри Рихтер. Дополнительные возможности AsyncEnumerator (http://msdn.microsoft.com/ru-ru/magazine/cc721613.aspx)
![Page 73: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/73.jpg)
Дополнительные ссылки
Итераторы в языке программирования C# Часть 1: http://sergeyteplyakov.blogspot.com/2010/06/c-1.html Часть 2: http://sergeyteplyakov.blogspot.com/2010/06/c-2.html Часть 3: http://sergeyteplyakov.blogspot.com/2010/06/c-3.html
Eric Lippert. Continuation Passing Style: http://blogs.msdn.com/b/ericlippert/archive/tags/continuation+passing+style/
Reactive Extensions Official release (http://channel9.msdn.com/Blogs/Charles/Announcing-the-Official-Release-of-Rx)
![Page 74: Luxoft async.net](https://reader036.fdocuments.net/reader036/viewer/2022062405/554f4732b4c905524c8b46c9/html5/thumbnails/74.jpg)
Вопросы?