1
©LuxoftTraining2013
06 июля 2013
Тонкости асинхронного
программирования
Dev Labs
2
©LuxoftTraining2013
Эволюция языка C#
3
©LuxoftTraining2013
Sync vs Async
Synchronous
Perform something here and now.
I’ll regain control to execute something e...
4
©LuxoftTraining2013
Sync vs Async
Caller Srv
Foo
42
Caller Srv
Operation finished
Result: 42
FooAsync
Operation Started
...
5
©LuxoftTraining2013
Sync vs Async
var webRequest = WebRequest.Create(Url); 
using (var response = webRequest.GetResponse...
6
©LuxoftTraining2013
Sync vs Async (2)
var webRequest = WebRequest.Create(Url); 
using (var response = await webRequest.G...
7
©LuxoftTraining2013
Demo – sync 2 async
8
©LuxoftTraining2013
Если вы думаете, что
асинхронное программирование
стало проще!
9
©LuxoftTraining2013
Копайте в глубь!
Все нетривиальные абстракции дырявы
Джоэл Спольски «Закон дырявых абстракций»
Вы до...
10
©LuxoftTraining2013
Async/await – лишь вершина
11
©LuxoftTraining2013
Synchronization Context
 Некоторые типы приложений налагают
ограничения на «потоковую» модель
 Co...
12
©LuxoftTraining2013
Зачем мне это?
Я же программирую на C#
5.0!
13
©LuxoftTraining2013
private int GetAnswerToUltimateQuestion()
{
    buttonRun.Enabled = false;
    Thread.Sleep(1000);
...
14
©LuxoftTraining2013
private async Task<int> GetAnswerToUltimateQuestionAsync()
{
    buttonRun.Enabled = false;
    awa...
15
©LuxoftTraining2013
Другими словами…
private Task<int> GetAnswerToUltimateQuestionAsyncImpl()
{
    buttonRun.Enabled =...
17
©LuxoftTraining2013
“Sync over Async” + UI ==
Deadlock!
18
©LuxoftTraining2013
Решение
private async Task<int> GetAnswerAsync() 
{ 
    await Task.Delay(10); 
    return 42; 
} 
...
19
©LuxoftTraining2013
Где вылетит ошибка?
var ms = new MemoryStream();           
// Здесь? 
Task<int> task = ms.ReadAsyn...
20
©LuxoftTraining2013
«Наивная» реализация
public static async Task<int> ReadAsync(byte[] buffer) 
{ 
    if (buffer == n...
21
©LuxoftTraining2013
Корректная реализация
public static Task<int> ReadAsync(byte[] buffer) 
{ 
    if (buffer == null) ...
22
©LuxoftTraining2013
Await исключений
public static async Task<int> SimpleAsync() 
{ 
    throw new CustomException(); 
...
23
©LuxoftTraining2013
Обработка нескольких исключений
public static async Task FooAsync() 
{ 
    // t1 "падает" 
    Tas...
24
©LuxoftTraining2013
Unobserved Exceptions
 Событие TaskScheduler.UnobservedException
 Генерируется финализатором
 Не...
25
©LuxoftTraining2013
“Решение”
public static async Task FooAsync()
{ 
   // t1 "падает" 
   Task<int> t1 = Task<int>.Fac...
26
©LuxoftTraining2013
Структура исключений
AggregateException
task.ContinueWith()
AggregateException
Task.WhenAll(t1, t2)...
27
©LuxoftTraining2013
И как это дело ловить?
var task = Modified.FooAsync(); 
try 
{ 
    await task; 
} 
// Для случая б...
28
©LuxoftTraining2013
Асинхронные методы
 Типы возвращаемого значения асинхронного
метода:
 async void FooAasync() – Fi...
29
©LuxoftTraining2013
Где вылетит ошибка?
private static async void FooAsync()
{
throw new Exception("Ooops!");
}
It Dep...
30
©LuxoftTraining2013
Demo – async void exceptions
31
©LuxoftTraining2013
Задача: убедиться, что метод генерирует
исключение!
32
©LuxoftTraining2013
Naïve Approach
public static async Task FooAsync()
{
//throw new InvalidOperationException("Oops!")...
33
©LuxoftTraining2013
Рабочий вариант!
[Test]
public void Test_FooAsync_Throws()
{
// Sync over Asyc? ;)
ThrowsAsync<Inva...
34
©LuxoftTraining2013
Async Guidelines
 Async void – это операции вида “fire-and-forget”
 Вызывающий код не может узнат...
35
©LuxoftTraining2013
Сколько же тут всего…
 Влияние TAP на дизайн приложения!
 Обработка исключений
 Unobserved excep...
36
©LuxoftTraining2013
Вот этого не надо
- Как вы пишите софт?
- Бац-бац и в продакшн (с).
- Как из синхронного приложения...
37
©LuxoftTraining2013
Его высочество Async …
не так прост, как кажется;)
38
©LuxoftTraining2013
Что думает по этому поводу Eric Lippert?
Q: C# 5.0 has new feature called async/await. Why
should d...
39
©LuxoftTraining2013
Дополнительные ссылки
 pfxteam blog
 C# Async Tips and Tricks Part 2: Async Void
 MVP Summit pre...
40
©LuxoftTraining2013
!Благодарю за внимание
?Вопросы
41
©LuxoftTraining2013
IntHR
Luxtown
Информация об учебном центре
www.luxoft-training.ru/about
Расписание
www.luxoft-train...
Upcoming SlideShare
Loading in …5
×

Тонкости асинхронного программирования

1,533 views

Published on

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,533
On SlideShare
0
From Embeds
0
Number of Embeds
9
Actions
Shares
0
Downloads
14
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide
  • Первый слайд всего курса.
  • Просто для того, чтобы с чего-нибудь начать разговор и подойти к сегодняшней теме я бы хотел немного напомнить историю развития платформы .NET и языка C# . Это даст нам понять то, как же мы докатились до такой жизни. В целом, нас интересует два последних релиза языка C# , которые и дали основной толчок асинхронному программированию на платформе .NET . И да, вам не послышалось и я не оговорился, именно два последних релиза сделали асинхронное программирование таким, каким мы его знаем сегодня, а не один последний релиз. В C# 4.0 ( а точнее в .NET Framework 4.0) появилась TPL , а в C# 5.0 (и .NET 4.5 ) эта модель асинхронного программирования стала повсеместной; и не последнюю роль в этом вопросе сыграли новые возможности языков C# и VB . NET . Давайте посмотрим, к чему же мы стремились.
  • С одной стороны, асинхронное программирование на платформе .NET существовало с самой первой ее версии (в виде так называемой Asynchronous Programming Model ), а с другой стороны асинхронное программирование всегда было на порядок сложнее с точки зрения реализации, отладки и сопровождения, по сравнению с синхронной версией. Основная же цель новых «асинхронных» возможностей языка C# была направлена на «унификацию» синхронного и асинхронного программирования. Решить проблему асинхронности путем добавления пары ключевых слов в тело и заголовок методов, чтобы сделать их асинхронными. И это просто прекрасно, но сразу же после выхода этого дела в свет стало ясно, что у этой простоты есть своя цена! На самом деле, я могу
  • TODO: выделить ключевые слова и Async , чтобы изменения были более видны
  • Главная цель моего выступления заключается в том, чтобы немного сместить акцент с языковых конструкций, которые появлись в C# и VB с выходом VS2012 . Разобраться с новыми ключевыми словами не требует больших усилий, однако для написания нормального асинхронного кода все равно нужно понимать, что происходит внутри. О новых языковых возможностях не рассказывал и не писал только ленивый. В любой новой книге по языку C# , в любом выступлении на конференции об этом говорится. Но уже сейчас становится понятно, что та простота, которой так хотели добиться разработчики обладает и негативной стороной. Единственной сессией на MVP саммите в этом году было выступление Стивена Тауба и Лушиана Вишика о проблемах async void методах. Это первый такой звоночек, который говорит, что слишком многие относятся к новым возможностям слишком уж легкомысленно. Поэтому сегодня я хочу дать основные понятия и концепции, которые стоит изучить более подробно, чтобы стать асинхронным гуру!
  • Абстракции текут и чтобы понимать что-то нам нужно разбираться на один уровень абстракции ниже!
  • Обязательно сказать и продумать про разные типы приложений!!
  • Когда речь заходит за UI потоки, то любой join асинхронной операции может привести к deadlock -у. В этом случае работает следующее правило: если вы начали использовать асинхронные операции, то их следует продолжать использование, а не ожидать их завершения (явно или неявно).
  • Что будет в этом случае? Будет ли проброшено исключение первой задачи, второй задачи, обеих задач в виде AggregateException ?
  • Очень печально, но в данном случае наружу вылетит лишь первое из возникших исключений! Я так и не смог добиться получения наружу обоих исключений!!
  • Principles Async void is a “fire-and-forget” mechanism... The caller is unable to know when an async void has finished The caller is unable to catch exceptions thrown from an async void (instead they get posted to the UI message-loop) Guidance Use async void methods only for top-level event handlers (and their like) Use async Task-returning methods everywhere else When you see an async lambda, verify it
  • Найти рисунок и цитату типа «тяп-ляп и в продакшн»
  • Тонкости асинхронного программирования

    1. 1. 1 ©LuxoftTraining2013 06 июля 2013 Тонкости асинхронного программирования Dev Labs
    2. 2. 2 ©LuxoftTraining2013 Эволюция языка C#
    3. 3. 3 ©LuxoftTraining2013 Sync vs Async Synchronous Perform something here and now. I’ll regain control to execute something else when it’s done.
    4. 4. 4 ©LuxoftTraining2013 Sync vs Async Caller Srv Foo 42 Caller Srv Operation finished Result: 42 FooAsync Operation Started Bckgn Starting background operation Notifies t t t0 Sync vs Async
    5. 5. 5 ©LuxoftTraining2013 Sync vs Async var webRequest = WebRequest.Create(Url);  using (var response = webRequest.GetResponse())  {      using (var file = new FileStream(FileName,           FileMode.OpenOrCreate))      {          var length = response.ContentLength;          var textWriter = new StreamWriter(file);          textWriter.Write(length.ToString());          textWriter.Close();      }  }
    6. 6. 6 ©LuxoftTraining2013 Sync vs Async (2) var webRequest = WebRequest.Create(Url);  using (var response = await webRequest.GetResponseAsync())  {      using (var file = new FileStream(FileName,           FileMode.OpenOrCreate))      {          var length = response.ContentLength;          var textWriter = new StreamWriter(file);          await textWriter.WriteAsync(length.ToString());          textWriter.Close();      }  }
    7. 7. 7 ©LuxoftTraining2013 Demo – sync 2 async
    8. 8. 8 ©LuxoftTraining2013 Если вы думаете, что асинхронное программирование стало проще!
    9. 9. 9 ©LuxoftTraining2013 Копайте в глубь! Все нетривиальные абстракции дырявы Джоэл Спольски «Закон дырявых абстракций» Вы должны понимать как минимум на один уровень абстракции ниже того уровня, на котором вы кодируете Ли Кэмпбел (Lee Campbell)
    10. 10. 10 ©LuxoftTraining2013 Async/await – лишь вершина
    11. 11. 11 ©LuxoftTraining2013 Synchronization Context  Некоторые типы приложений налагают ограничения на «потоковую» модель  Control.Invoke/BeginInvoke  Dispatcher.Invoke/BeginInvoke  Контекст синхронизации «прячет» эти детали за абстрактным интерфейсом  Контекст нужен для «маршалинга» управления из одного потока в другой (*)  Контексты повсюду!
    12. 12. 12 ©LuxoftTraining2013 Зачем мне это? Я же программирую на C# 5.0!
    13. 13. 13 ©LuxoftTraining2013 private int GetAnswerToUltimateQuestion() {     buttonRun.Enabled = false;     Thread.Sleep(1000);     buttonRun.Enabled = true;     return 42; } private void buttonRun_Click_Sync(object sender, EventArgs e) {     int result = GetAnswerToUltimateQuestion();     textBoxStatus.Text = result.ToString(); } Sync Version Некоторая длительная операция!!
    14. 14. 14 ©LuxoftTraining2013 private async Task<int> GetAnswerToUltimateQuestionAsync() {     buttonRun.Enabled = false;     await Task.Delay(1000);     buttonRun.Enabled = true;     return 42; } private void buttonRun_Click_Async(object sender, EventArgs e) {     Task<int> result = GetAnswerToUltimateQuestionAsync();     textBoxStatus.Text = result.Result.ToString(); } Наивный подход… [Thread 2] Ожидает освобождения UI потока [Thread 1] Ожидает завершения асинхронной операции Захватываем Sync Context Возвращает управление!
    15. 15. 15 ©LuxoftTraining2013 Другими словами… private Task<int> GetAnswerToUltimateQuestionAsyncImpl() {     buttonRun.Enabled = false;     var task = LongRunningTask();     return task.ContinueWith(t =>         {             buttonRun.Enabled = true;             return 42;         }, TaskScheduler.FromCurrentSynchronizationContext()); } private void buttonRun_Click_Async_Impl(object sender, EventArgs e) {     Task<int> result = GetAnswerToUltimateQuestionAsyncImpl();     textBoxStatus.Text = result.Result.ToString(); }
    16. 16. 17 ©LuxoftTraining2013 “Sync over Async” + UI == Deadlock!
    17. 17. 18 ©LuxoftTraining2013 Решение private async Task<int> GetAnswerAsync()  {      await Task.Delay(10);      return 42;  }  private async void btn_Click(object sender,      EventArgs e)  {      label.Text = (await GetAnswerAsync()).ToString();  }
    18. 18. 19 ©LuxoftTraining2013 Где вылетит ошибка? var ms = new MemoryStream();            // Здесь?  Task<int> task = ms.ReadAsync(null, 0, 42);  // Или здесь?  int result = task.Result; • Является исключение «синхронным» или «асинхронным»?
    19. 19. 20 ©LuxoftTraining2013 «Наивная» реализация public static async Task<int> ReadAsync(byte[] buffer)  {      if (buffer == null)           throw new ArgumentNullException("buffer");      // Реализация асинхронного чтения      return 42;  } Результирующая задача перейдет в Faulted состояние! • Синхронное исключение означает «баг» в вызывающем коде. • «Поломанная» задача означает баг в реализации! Зачем заморачиваться?
    20. 20. 21 ©LuxoftTraining2013 Корректная реализация public static Task<int> ReadAsync(byte[] buffer)  {      if (buffer == null)           throw new ArgumentNullException("buffer");      return ReadAsyncImpl(buffer);  }  private static async Task<int> ReadAsyncImpl(byte[] buffer)  {      // Реализация асинхронногочтения      return 42;  } Синхронная проверка «предусловий» Блоки итераторов ведут себя аналогично!
    21. 21. 22 ©LuxoftTraining2013 Await исключений public static async Task<int> SimpleAsync()  {      throw new CustomException();  }  public static async void ConsumeSimpleAsync()  {      var task = SimpleAsync();      try      {          // "Разыменовывание" задачи приводит к          // "разворачиванию" первого исключения!          int result = await task;      }      catch (CustomException)      {          Console.WriteLine("Yahoo!!!");      }  }
    22. 22. 23 ©LuxoftTraining2013 Обработка нескольких исключений public static async Task FooAsync()  {      // t1 "падает"      Task<int> t1 = Task<int>.Factory.StartNew(() =>      {          throw new Exception("E1");      });      // t2 тоже "падает"      Task<int> t2 = Task<int>.Factory.StartNew(() =>      {          throw new Exception("E2");      });      int r1 = await t1;      int r2 = await t2;  } Получим “E1”? Получим “E2”? Получим AggregateException? UnobservedTaskException!
    23. 23. 24 ©LuxoftTraining2013 Unobserved Exceptions  Событие TaskScheduler.UnobservedException  Генерируется финализатором  Не вызывается при обращении к  Result  Exception  Вызове Wait  Поведение зависит от версии .NET Framework  .NET 4.5 – «умалчивается» (*)  .NET 4.0 – «ломает» приложение
    24. 24. 25 ©LuxoftTraining2013 “Решение” public static async Task FooAsync() {     // t1 "падает"     Task<int> t1 = Task<int>.Factory.StartNew(() =>     {         throw new Exception("E1");     });      // t2 тоже "падает"     Task<int> t2 = Task<int>.Factory.StartNew(() =>     {         throw new Exception("E2");     });      // "Наблюдаем" оба исключения     var task = Task.WhenAll(t1, t2);     await task.ContinueWith(_ => _.Result);         int r1 = t1.Result;     int r2 = t2.Result; } «Объединяем» обе задачи await task; пробросил бы лишь первое исключение!Явно генерируем AggregateException!!!!
    25. 25. 26 ©LuxoftTraining2013 Структура исключений AggregateException task.ContinueWith() AggregateException Task.WhenAll(t1, t2); First Exception("E1") t1: Task Exception("E2") t2: Task First Second await вытянет первое исключение и получит AggregateException! Task.WhenAll(t1, t2); await  task.ContinueWith(_ => _.Result);
    26. 26. 27 ©LuxoftTraining2013 И как это дело ловить? var task = Modified.FooAsync();  try  {      await task;  }  // Для случая более одного исключения  catch (AggregateException e)  {      // "Выпрямляем" все исключения      int count = e.Flatten().InnerExceptions.Count;      Console.WriteLine(         "Demo2.Modified.FooAsync failed with {0} exceptions",          count);  }  // Для более простых случаев  catch (CustomException e) { }  catch (Exception e) {}
    27. 27. 28 ©LuxoftTraining2013 Асинхронные методы  Типы возвращаемого значения асинхронного метода:  async void FooAasync() – Fire and Forget (*)  async Task FooAsync() – (void Foo())  async Task<T> FooAsync() – (T Foo())
    28. 28. 29 ©LuxoftTraining2013 Где вылетит ошибка? private static async void FooAsync() { throw new Exception("Ooops!"); } It Depends!
    29. 29. 30 ©LuxoftTraining2013 Demo – async void exceptions
    30. 30. 31 ©LuxoftTraining2013 Задача: убедиться, что метод генерирует исключение!
    31. 31. 32 ©LuxoftTraining2013 Naïve Approach public static async Task FooAsync() { //throw new InvalidOperationException("Oops!"); await Task.Delay(42); } [Test] public async void Test_FooAsync_Throws_1() { try { await FooAsync(); Assert.Fail("InvalidOperation was not thrown"); } catch (InvalidOperationException) { } } [Test] public async void Test_FooAsync_Throws_2() { Assert.Throws<InvalidOperationException>(async () => await FooAsync()); }
    32. 32. 33 ©LuxoftTraining2013 Рабочий вариант! [Test] public void Test_FooAsync_Throws() { // Sync over Asyc? ;) ThrowsAsync<InvalidOperationException>(FooAsync).Wait(); } public async static Task ThrowsAsync<T>(Func<Task> testCode) where T : Exception { try { await testCode(); // Если мы сюда попадем, то движок NUnit // бросит нужный тип исключения Assert.Throws<T>(() => { }); } catch (T) {} }
    33. 33. 34 ©LuxoftTraining2013 Async Guidelines  Async void – это операции вида “fire-and-forget”  Вызывающий код не может узнать о завершении асинхронного метода  Вызывающий код не может обработать исключения (вместо этого они попадут в цикл обработки UI сообщений или «уронят» приложение!)  Используйте async void только для обработчиков событий самого высокого уровня.  Используйте возвращаемые значения!  Осторожнее с асинхронными лямбда- выражениями!
    34. 34. 35 ©LuxoftTraining2013 Сколько же тут всего…  Влияние TAP на дизайн приложения!  Обработка исключений  Unobserved exceptions  Bugs vs Task Faults  Гранулярность асинхронных операций  Testability  Work stealing
    35. 35. 36 ©LuxoftTraining2013 Вот этого не надо - Как вы пишите софт? - Бац-бац и в продакшн (с). - Как из синхронного приложения сделать асинхронное? - Async/await и готово!
    36. 36. 37 ©LuxoftTraining2013 Его высочество Async … не так прост, как кажется;)
    37. 37. 38 ©LuxoftTraining2013 Что думает по этому поводу Eric Lippert? Q: C# 5.0 has new feature called async/await. Why should developers be excited about it? A: People like me, are excited about this feature because its a cooperative multitasking with coroutines implementing using continuation passing style.
    38. 38. 39 ©LuxoftTraining2013 Дополнительные ссылки  pfxteam blog  C# Async Tips and Tricks Part 2: Async Void  MVP Summit presentation on async  Знакомство с асинхронными операциями в C# 5
    39. 39. 40 ©LuxoftTraining2013 !Благодарю за внимание ?Вопросы
    40. 40. 41 ©LuxoftTraining2013 IntHR Luxtown Информация об учебном центре www.luxoft-training.ru/about Расписание www.luxoft-training.ru/timetable Каталог курсов www.luxoft-training.ru/training/catalog_directions Контакты www.luxoft-training.ru/contacts www.facebook.com/TrainingCenterLuxoft Расписание, курсы, тренеры Условия обучения, логистика, контакты Luxtown Информационные ресурсы Luxoft Training

    ×