Your SlideShare is downloading. ×
Luxoft async.net
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Luxoft async.net

597

Published on

Презентация по асинхронному программированию в .net

Презентация по асинхронному программированию в .net

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
597
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
10
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Асинхронноепрограммирование в .NetСергей ТепляковSTeplyakov@luxoft.com
  • 2. О Вашем инструкторе Сергей Тепляков Visual C# MVP, RSDN Team member Sergey.Teplyakov@gmail.com SergeyTeplyakov.blogspot.com 1-2
  • 3. Цели курса…Слушатели изучат: Достоинства и недостатки синхронного программирования Существующие паттерны асинхронного программирования на платформе .Net Использование библиотеки PowerThreading Использование библиотеки TPL Новые возможности C# 5 1-3
  • 4. Необходимая подготовкаСлушатели должны: Быть знакомы с основами языка C# и платформы .Net Обладать базовыми знаниями многопоточности 1-4
  • 5. Roadmap Модель синхронного программирования Паттерны асинхронного программирования на платформе .Net Недостатки существующих моделей Библиотека PowerThreading Библиотека TPL C# 5.0: async и await 1-5
  • 6. Недостатки синхронногопрограммирования Плохая масштабируемость Блокирование пользовательского интерфейса Низкая эффективность операций ввода/вывода Невозможность использования в некоторых контекстах (например, с JavaScript и Silverlight)
  • 7. Плохая масштабируемость.последовательное выполнение sd Sync Client HttpWebRequest webRequest1.GetWebResponce() ProcessWebResponce1() webRequest2.GetWebResponce() ProcessWebResponce2()
  • 8. Плохая масштабируемость Неэффективное использование мощностей современных многоядерных процессоров для CPU-Bound операций Неэффективное выполнение IO-Bound операций даже для одноядерных процессоров
  • 9. Блокировка пользовательскогоинтерфейса
  • 10. Блокировка пользовательскогоинтерфейса// Обработчик кнопки получения данных от веб-страниц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(); } }}
  • 11. А ведь это и не всегдавозможно! Некоторые среды, такие как Silverlight и JavaScript не поддерживают синхронные операции
  • 12. Рассматриваемые темы Модель синхронного программирования Паттерны асинхронного программирования на платформе .Net Недостатки существующих моделей Библиотека PowerThreading Библиотека TPL C# 5.0: async и await
  • 13. Асинхронная модельпрограммирования Два паттерна асинхронного программирования  Classical Async Pattern  Event-Based Async Pattern
  • 14. 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);
  • 15. Classical Async Pattern Метод BeginXXX инициирует асинхронную операцию Метод BeginXXX возвращает IAsyncResult, который является маркером асинхронной операции AsyncCallback представляет собой функцию, которая будет вызвана при завершении операции State представляет собой любой пользовательский объект
  • 16. Classical Async Pattern Все by-value и by-ref параметры синхронного метода становятся by-value параметрами BeginXXX метода Тип возвращаемого значения синхронного метода совпадает с типом возвращаемого значения EndXXX метода ref и out параметры синхронного метода добавляются в EndXXX метод Исключения, генерируемые синхронным методом, генерируются методом EndXXX
  • 17. Примеры Classical AsyncPattern Класс 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);
  • 18. Асинхронное выполнениеsd ClassicAsync Form Client HttpWebRequest IO completion webRequest1.BeginGetResponse() webRequest2.BeginGetResponse() webRequest2.ProcessResponse() ProcessResponse() UpdateUIElements() webRequest1.ProcessResponse() ProcessResponse() UpdateUIElements()
  • 19. Classical Async Pattern В обработчике UI события:  Проинициализировать дополнительные поля (теперь без них не обойтись)  Сделать неактивной кнопку  В цикле начать все операции асинхронно (вызывать метод BeginGetResponse)
  • 20. Classical Async Pattern В обработчике завершения асинхронной операции:  Получить WebResponse (вызывать метод EndGetReponse)  Обработать ответ, не забывая, что обработка происходит не в потоке UI  Понять, что все асинхронные операции завершены (??) (посчитать количество завершенных операций)  Сделать активной кнопку, если все операции таки завершены  Если перед началом выполнения асинхронных операций были выделены ресурсы, то освободить их вручную
  • 21. Разница синхронного иасинхронного вариантов длятрех веб-узлов Среднее выполнение синхронного варианта: 520мс Среднее выполнение асинхронного варианта: 280 мс Количество строк кода в синхронном решении: 20 Количество строк кода в асинхронном решении: 78
  • 22. Event-Based Async Pattern
  • 23. Event-Based Async Patternclass Class Model AsyncCompletedEv entArgs Находится в пространстве + Canceled: bool имен: System.ComponentModel Событие MethodCompleted + Error: Exception вызывается как при успешном, + UserState: object так и при неудачном завершении метода. Метод CancelMethod и событие ProgressChanged являются опциональными. MethodCompletedEv entArgs SomeType Uses + Arg1: int + event MethodCompleted + Arg2: string + event ProgressChanged + Result: MethodResult + CancelMethod() : void Uses + MethodAsync(string, int) : void MethodResult
  • 24. Event-Based Async Pattern MethodAsync инициирует асинхронную операцию Есть только одно событие MethodCompleted, EventArgs которого содержат Result, Error, IsCanceled Возможна, но не обязательна, поддержка отмены и прогресса выполнения
  • 25. Event-Based Async Pattern By-value и ref параметры синхронного метода являются входными параметрами метода MethodAsync Ref и out-параметры становятся readonly полями MethodCompletedEventArgs Событие MethodCompleted вызывается в «правильном» потоке (в потоке UI для WinForms или WPF)
  • 26. 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. // Обработка результатов }; }}
  • 27. Да как же между нимивыбрать? Классический паттерн более низкоуровневый и более гибкий Event-Based паттерн более простой в применении, в частности с UI дизайнерами Классический паттерн – для кода общего назначения, Event-Based – для компонентов Не применяйте оба паттерна для одного класса
  • 28. Рассматриваемые темы Модель синхронного программирования Паттерны асинхронного программирования на платформе .Net Недостатки существующих моделей Библиотека PowerThreading Библиотека TPL C# 5.0: async и await
  • 29. Недостатки моделейасинхронного программирования Непонятный поток исполнения (Control Flow) Сложность чтения кода и его сопровождения Сложность обработки ошибок Невозможность использования привычных языковых конструкций (using, try/finally etc)
  • 30. Рассматриваемые темы Модель синхронного программирования Паттерны асинхронного программирования на платформе .Net Недостатки существующих моделей Библиотека PowerThreading Библиотека TPL C# 5.0: async и await
  • 31. PowerThreading Library Разработана Джеффри Рихтер и компанией Wintellect Содержит класс AsyncEnumerator для упрощения работы с асинхронными операциями Содержит вспомогательные классы для работы с многопоточностью (ResourceLock, ReaderWriterGate etc) Другие вспомогательные классы (Disposer, Exception<T>, Singleton etc)
  • 32. Класс AsyncEnumerator.Основные концепции Поддерживает гибкое управление асинхронными операциями (отмену, таймауты и т.п.) Использует преимущество блока итераторов (Iterator block) для упрощения потока исполнения Использует SynchronizationContext для маршалинга потока выполнения в поток UI
  • 33. Класс 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);
  • 34. Отступление от темы. Блокиитераторовstatic IEnumerator<int> GetNumbers(){ string padding = "tt"; 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");}
  • 35. Визуализация итераторов static IEnumerator<int> GetNumbers()WriteLine("Вызываем GetNumbers()"); {IEnumerator<int> iterator = GetNumbers(); string padding = "tt"; Console.WriteLine(padding + "Первая строка метода GetNumbers()"); // 1WriteLine("Вызываем MoveNext()..."); Console.WriteLine(padding + "Сразу перед yield return 7"); // 2bool more = iterator.MoveNext(); yield return 7; // 3WriteLine("Result=...", iterator.Current); Console.WriteLine(padding + "Сразу после yield return 7"); // 4 Console.WriteLine(padding + "Сразу перед yield return 42"); // 5WriteLine("Снова вызываем MoveNext()..."); yield return 42; // 6more = iterator.MoveNext(); Console.WriteLine(padding + "Сразу после yield return 42"); //7WriteLine("Result=...", iterator.Current); }WriteLine("Снова вызываем MoveNext()...");more = iterator.MoveNext();WriteLine("Result={0} (stopping)", more);Результат:Вызываем GetNumbers()
  • 36. Визуализация итераторов static IEnumerator<int> GetNumbers()WriteLine("Вызываем GetNumbers()"); {IEnumerator<int> iterator = GetNumbers(); string padding = "tt"; Console.WriteLine(padding + "Первая строка метода GetNumbers()");WriteLine("Вызываем MoveNext()..."); Console.WriteLine(padding + "Сразу перед yield return 7");bool more = iterator.MoveNext(); yield return 7;WriteLine("Result=...", iterator.Current); Console.WriteLine(padding + "Сразу после yield return 7"); Console.WriteLine(padding + "Сразу перед yield return 42");WriteLine("Снова вызываем MoveNext()..."); yield return 42; // 6more = iterator.MoveNext(); Console.WriteLine(padding + "Сразу после yield return 42");WriteLine("Result=...", iterator.Current); }WriteLine("Снова вызываем MoveNext()...");more = iterator.MoveNext();WriteLine("Result={0} (stopping)", more);Результат:Вызываем GetNumbers()Вызываем MoveNext()... Первая строка метода GetNumbers() Сразу перед yield return 7Result=True; Current=7
  • 37. Визуализация итераторов static IEnumerator<int> GetNumbers()WriteLine("Вызываем GetNumbers()"); {IEnumerator<int> iterator = GetNumbers(); string padding = "tt"; Console.WriteLine(padding + "Первая строка метода GetNumbers()");WriteLine("Вызываем MoveNext()..."); Console.WriteLine(padding + "Сразу перед yield return 7");bool more = iterator.MoveNext(); yield return 7;WriteLine("Result=...", iterator.Current); Console.WriteLine(padding + "Сразу после yield return 7"); Console.WriteLine(padding + "Сразу перед yield return 42");WriteLine("Снова вызываем MoveNext()..."); yield return 42;more = iterator.MoveNext(); Console.WriteLine(padding + "Сразу после yield return 42");WriteLine("Result=...“, iterator.Current); }WriteLine("Снова вызываем MoveNext()...");more = iterator.MoveNext();WriteLine("Result={0} (stopping)", more);Результат:Вызываем GetNumbers()Вызываем MoveNext()... Первая строка метода GetNumbers() Сразу перед yield return 7Result=True; Current=7Снова вызываем MoveNext()... Сразу после yield return 7 Сразу перед yield return 42Result=True; Current=42
  • 38. Визуализация итераторов static IEnumerator<int> GetNumbers()WriteLine("Вызываем GetNumbers()"); {IEnumerator<int> iterator = GetNumbers(); string padding = "tt"; Console.WriteLine(padding + "Первая строка метода GetNumbers()");WriteLine("Вызываем MoveNext()..."); Console.WriteLine(padding + "Сразу перед yield return 7");bool more = iterator.MoveNext(); yield return 7;WriteLine("Result=...", iterator.Current); Console.WriteLine(padding + "Сразу после yield return 7"); Console.WriteLine(padding + "Сразу перед yield return 42");WriteLine("Снова вызываем MoveNext()..."); yield return 42;more = iterator.MoveNext(); Console.WriteLine(padding + "Сразу после yield return 42");WriteLine("Result=...", iterator.Current); }WriteLine("Снова вызываем MoveNext()...");more = iterator.MoveNext();WriteLine("Result={0} (stopping)", more);Результат:Вызываем GetNumbers()Вызываем MoveNext()... Первая строка метода GetNumbers() Сразу перед yield return 7Result=True; Current=7Снова вызываем MoveNext()... Сразу после yield return 7 Сразу перед yield return 42Result=True; Current=42Result=False (stopping)
  • 39. AsyncEnumerator. Участники Класс AsyncEnumerator Рабочий метод, возвращающий IEnumerator<int> Кто-то, связывающий все это воедино
  • 40. AsyncEnumeratorsd AsyncEnumerator AsyncEnumerator WorkerMethod WebRequest IO Completion calling to MoveNext() webRequest1.BeginGetResponse() Первый вызов MoveNext енумератора инициирует ас инхронные операции. webRequest2.BeginGetResponse() WebRequest2Complete() WebRequest1Complete() calling to MoveNext() Т еперь рабочий метод В качес тве метода обработки (WorkerMethod) может обработать завершения ас инхронной завершенные операции и начать операции передаетс я метод новые ас инхронные операции. клас с а AsyncEnumerator-а.
  • 41. Пример использования классаAsyncEnumeratorprivate 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()); // Обрабатываем полученные результаты аналогичным образом}
  • 42. Пример использования классаAsyncEnumeratorprivate void receiveDataButton_Click(object sender, EventArgs e){ asyncEnumerator = new AsyncEnumerator(); // AsyncEnumerator автоматически запоминает контекст синхронизации // Запускаем процесс получения данных асинхронно asyncEnumerator.BeginExecute(GetWebData(asyncEnumerator), asyncEnumerator.EndExecute);}
  • 43. Рассматриваемые темы Модель синхронного программирования Паттерны асинхронного программирования на платформе .Net Недостатки существующих моделей Библиотека PowerThreading Библиотека TPL C# 5.0: async и await
  • 44. Библиотека TPL Параллелизм задач Класс Parallel (Parallel.ForEach etc) Parallel LINQ (a.k.a. PLINQ)
  • 45. Ключевые классы Task – инкапсулирует единицу работы Task<TResult> - единица работы с определенным типом результата TaskFactory, TaskFactory<TResult> – фабрики создания задач TaskScheduler – управляет «расписанием» запуска задач TaskCompletionSource – управляет «временем жизни» задачи
  • 46. Класс Task<T> Представляет собой «незавершенную операцию» или «единицу работы» Это может быть операция ввода/вывода, операция в фоновом потоке, в выделенном потоке и т.д. Поддерживает «продолжения» с помощью ContinueWithvar task2 = task1.ContinueWith(t => … t.Result …); Содержит ряд вспомогательных методов: WhenAll, WhenAny etc
  • 47. Примеры использования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);
  • 48. Примеры использования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;
  • 49. ПродолженияTask task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));// Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены");
  • 50. ПродолженияTask task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));// Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены"); Вывод: (ничего не происходит, поскольку задача еще не запущена)
  • 51. ПродолженияTask task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));// Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены"); Вывод: (все еще ничего не происходит, поскольку первая задача не запущена) (первой задаче установлена вторая задача в виде продолжения)
  • 52. ПродолженияTask task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));// Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены"); Вывод: (все еще ничего не происходит, поскольку первая задача не запущена) (Связке первых двух задач установлена третья задача в виде продолжения)
  • 53. ПродолженияTask task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));// Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены"); Вывод: Запускаем первую задачу
  • 54. ПродолженияTask task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));// Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены"); Вывод: Запускаем первую задачу Ожидаем завершения цепочки задач
  • 55. ПродолженияTask task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));// Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены"); Вывод: (Выполняется первая задача) Запускаем первую задачу Ожидаем завершения цепочки задач Task1...
  • 56. ПродолженияTask task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));// Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены"); Вывод: (Выполняется вторая задача, поскольку первая уже завершилась) Запускаем первую задачу Ожидаем завершения цепочки задач Task1... Task2...
  • 57. ПродолженияTask task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));// Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены"); Вывод: (Выполняется третья задача, поскольку первая и вторая уже завершились) Запускаем первую задачу Ожидаем завершения цепочки задач Task1... Task2... Task3...
  • 58. ПродолженияTask task1 = new Task(() => Console.WriteLine("Task1..."));Task task2 = task1.ContinueWith(t1 => Console.WriteLine("tTask2..."));Task task3 = task2.ContinueWith(t2 => Console.WriteLine("ttTask3..."));// Запускаем цепочку задачConsole.WriteLine("Запускаем первую задачу");task1.Start();Console.WriteLine("Ожидаем завершения цепочки задач");task3.Wait();Console.WriteLine("Все задачи завершены"); Вывод: (Выполняется третья задача, поскольку первая и вторая уже завершились) Запускаем первую задачу Ожидаем завершения цепочки задач Task1... Task2... Task3... Все задачи завершены
  • 59. Рассматриваемые темы Модель синхронного программирования Паттерны асинхронного программирования на платформе .Net Недостатки существующих моделей Библиотека PowerThreading Библиотека TPL C# 5.0: async и await
  • 60. Модель асинхронногопрограммирования в C# 5 Аналогична синхронной модели Построена по тому же принципу, что и класс AsyncEnumerator Использует Task<T> для асинхронных операций Никто не знает, когда выйдет C# 5 Сейчас доступно Async CTP (Community Technology Preview)
  • 61. Модель асинхронногопрограммирования в C# 5 Два новых ключевых слова:  async – указывает, что метод или лямбда- выражение является асинхронным  await – является аналогом yield return и возвращает сразу же управление вызывающему коду до тех пор, пока асинхронная операция не будет завершена
  • 62. Модель асинхронногопрограммирования в C# 5static 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;}
  • 63. Работа простого методаWriteLine("Начало исполнения. Thread Id: {0}"); static async Task<long> GetWebResponseContentLength(string url) {Task<long> task = var webRequest = WebRequest.Create(url); GetWebResponseContentLength(url); WriteLine("Перед вызовом await-a. Thread Id: {0}");// ожидаем завершения асинхронной операции // Начинаем асинхронную операциюtask.Wait(); Task<WebResponse> respTsk = webRequest.GetResponseAsync();WriteLine("ContentLength: {0}, Thread Id: {1}"); // Ожидаем получения ответа WebResponse webResponse = await respTsk; WriteLine("После завершения await-а. Thread Id: {0}"); Результаты: Начало исполнения. Thread Id: 10 return webResponse.ContentLength; } Перед вызовом await-a. Thread Id: 10 (Асинхронная операция запущена)
  • 64. Работа простого методаWriteLine("Начало исполнения. Thread Id: {0}"); static async Task<long> GetWebResponseContentLength(string url) {Task<long> task = var webRequest = WebRequest.Create(url); GetWebResponseContentLength(url); WriteLine("Перед вызовом await-a. Thread Id: {0}");// ожидаем завершения асинхронной операции // Начинаем асинхронную операциюtask.Wait(); Task<WebResponse> respTsk = webRequest.GetResponseAsync();WriteLine("ContentLength: {0}, Thread Id: {1}"); // Ожидаем получения ответа WebResponse webResponse = await respTsk; WriteLine("После завершения await-а. Thread Id: {0}"); Результаты: return webResponse.ContentLength; Начало исполнения. Thread Id: 10 } Перед вызовом await-a. Thread Id: 10 После завершения await-a. Thread Id: 14 (Эта строка выполнится только после завершения операции)
  • 65. Работа простого методаWriteLine("Начало исполнения. Thread Id: {0}"); static async Task<long> GetWebResponseContentLength(string url) {Task<long> task = var webRequest = WebRequest.Create(url); GetWebResponseContentLength(url); WriteLine("Перед вызовом await-a. Thread Id: {0}");// ожидаем завершения асинхронной операции // Начинаем асинхронную операциюtask.Wait(); Task<WebResponse> respTsk = webRequest.GetResponseAsync();WriteLine("ContentLength:{0},Thread Id: {1}"); // Ожидаем получения ответа WebResponse webResponse = await respTsk; WriteLine("После завершения await-а. Thread Id: {0}"); Результаты: return webResponse.ContentLength; } Начало исполнения. Thread Id: 10 Перед вызовом await-a. Thread Id: 10 После завершения await-a. Thread Id: 14 ContentLength: 1672, Thread Id: 10
  • 66. Сравнение с AsyncEnumerator IEnumerator<T> -> async Task<T> yield return n -> await task
  • 67. Модель асинхронногопрограммирования в C# 5 Асинхронный метод может возвращать  void – для асинхронных операций типа “fire and forget”  Task – вызывающий код может дождаться завершения асинхронной операции, которая не возвращает значения  Task<T> - для асинхронной операции, возвращающей T (string для Task<string> etc)
  • 68. Модель асинхронногопрограммирования C# 5private 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();}
  • 69. Преимущества новойасинхронной модели Простота использования Привычный поток исполнения Простота обработки ошибок и возможность использования конструкций using, try/finally etctry { WebResponse[] data = await TaskEx.WhenAll(tasks); // Обработка данных}catch (WebException we) { //Обработка ошибки получения данных}
  • 70. Преимущества новойасинхронной модели Построена на основе проверенных идиом (Iterator blocks, AsyncEnumerator, Reactive Extensions) Построена на основе TPL (преимущества от ее использования можно закладывать уже сейчас)
  • 71. Что мы изучили? Модель синхронного программирования Паттерны асинхронного программирования на платформе .Net Недостатки существующих моделей Библиотека PowerThreading Библиотека TPL C# 5.0: async и await
  • 72. Дополнительные ссылки 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)
  • 73. Дополнительные ссылки Итераторы в языке программирования 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+styl e/ Reactive Extensions Official release (http://channel9.msdn.com/Blogs/Charles/Announcing-the-Official-Release- of-Rx)
  • 74. Вопросы?

×