SlideShare a Scribd company logo
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 else
when it’s done.
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
©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
©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
©LuxoftTraining2013
Demo – sync 2 async
8
©LuxoftTraining2013
Если вы думаете, что
асинхронное программирование
стало проще!
9
©LuxoftTraining2013
Копайте в глубь!
Все нетривиальные абстракции дырявы
Джоэл Спольски «Закон дырявых абстракций»
Вы должны понимать как минимум на один
уровень абстракции ниже того уровня, на
котором вы кодируете
Ли Кэмпбел (Lee Campbell)
10
©LuxoftTraining2013
Async/await – лишь вершина
11
©LuxoftTraining2013
Synchronization Context
 Некоторые типы приложений налагают
ограничения на «потоковую» модель
 Control.Invoke/BeginInvoke
 Dispatcher.Invoke/BeginInvoke
 Контекст синхронизации «прячет» эти детали за
абстрактным интерфейсом
 Контекст нужен для «маршалинга» управления
из одного потока в другой (*)
 Контексты повсюду!
12
©LuxoftTraining2013
Зачем мне это?
Я же программирую на C#
5.0!
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
©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
©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();
}
17
©LuxoftTraining2013
“Sync over Async” + UI ==
Deadlock!
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(); 
}
19
©LuxoftTraining2013
Где вылетит ошибка?
var ms = new MemoryStream();           
// Здесь? 
Task<int> task = ms.ReadAsync(null, 0, 42); 
// Или здесь? 
int result = task.Result;
• Является исключение «синхронным» или «асинхронным»?
20
©LuxoftTraining2013
«Наивная» реализация
public static async Task<int> ReadAsync(byte[] buffer) 
{ 
    if (buffer == null) 
         throw new ArgumentNullException("buffer"); 
    // Реализация асинхронного чтения 
    return 42; 
}
Результирующая задача перейдет
в Faulted состояние!
• Синхронное исключение означает «баг» в вызывающем
коде.
• «Поломанная» задача означает баг в реализации!
Зачем заморачиваться?
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; 
}
Синхронная проверка
«предусловий»
Блоки итераторов ведут
себя аналогично!
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!!!"); 
    } 
}
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!
24
©LuxoftTraining2013
Unobserved Exceptions
 Событие TaskScheduler.UnobservedException
 Генерируется финализатором
 Не вызывается при обращении к
 Result
 Exception
 Вызове Wait
 Поведение зависит от версии .NET Framework
 .NET 4.5 – «умалчивается» (*)
 .NET 4.0 – «ломает» приложение
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!!!!
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);
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) {}
28
©LuxoftTraining2013
Асинхронные методы
 Типы возвращаемого значения асинхронного
метода:
 async void FooAasync() – Fire and Forget (*)
 async Task FooAsync() – (void Foo())
 async Task<T> FooAsync() – (T Foo())
29
©LuxoftTraining2013
Где вылетит ошибка?
private static async void FooAsync()
{
throw new Exception("Ooops!");
}
It Depends!
30
©LuxoftTraining2013
Demo – async void exceptions
31
©LuxoftTraining2013
Задача: убедиться, что метод генерирует
исключение!
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());
}
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)
{}
}
34
©LuxoftTraining2013
Async Guidelines
 Async void – это операции вида “fire-and-forget”
 Вызывающий код не может узнать о завершении
асинхронного метода
 Вызывающий код не может обработать
исключения
(вместо этого они попадут в цикл обработки UI
сообщений или «уронят» приложение!)
 Используйте async void только для обработчиков
событий самого высокого уровня.
 Используйте возвращаемые значения!
 Осторожнее с асинхронными лямбда-
выражениями!
35
©LuxoftTraining2013
Сколько же тут всего…
 Влияние TAP на дизайн приложения!
 Обработка исключений
 Unobserved exceptions
 Bugs vs Task Faults
 Гранулярность асинхронных операций
 Testability
 Work stealing
36
©LuxoftTraining2013
Вот этого не надо
- Как вы пишите софт?
- Бац-бац и в продакшн (с).
- Как из синхронного приложения сделать
асинхронное?
- Async/await и готово!
37
©LuxoftTraining2013
Его высочество Async …
не так прост, как кажется;)
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.
39
©LuxoftTraining2013
Дополнительные ссылки
 pfxteam blog
 C# Async Tips and Tricks Part 2: Async Void
 MVP Summit presentation on async
 Знакомство с асинхронными операциями в C# 5
40
©LuxoftTraining2013
!Благодарю за внимание
?Вопросы
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

More Related Content

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

Mobile automation uamobile
Mobile automation uamobileMobile automation uamobile
Mobile automation uamobile
UA Mobile
 
iPhone Unit Testing (Google tool Box)
iPhone Unit Testing (Google tool Box)iPhone Unit Testing (Google tool Box)
iPhone Unit Testing (Google tool Box)
Yandex
 

Similar to Тонкости асинхронного программирования (20)

Асинхронность и сопрограммы
Асинхронность и сопрограммыАсинхронность и сопрограммы
Асинхронность и сопрограммы
 
iOS and Android Mobile Test Automation
iOS and Android Mobile Test AutomationiOS and Android Mobile Test Automation
iOS and Android Mobile Test Automation
 
Mobile automation uamobile
Mobile automation uamobileMobile automation uamobile
Mobile automation uamobile
 
О.В.Сухорослов "Многопотчное программирование. Часть 2"
О.В.Сухорослов "Многопотчное программирование. Часть 2"О.В.Сухорослов "Многопотчное программирование. Часть 2"
О.В.Сухорослов "Многопотчное программирование. Часть 2"
 
JPoint 2016 - Etudes of DIY Java profiler
JPoint 2016 - Etudes of DIY Java profilerJPoint 2016 - Etudes of DIY Java profiler
JPoint 2016 - Etudes of DIY Java profiler
 
Григорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизацияГригорий Демченко, Асинхронность и неблокирующая синхронизация
Григорий Демченко, Асинхронность и неблокирующая синхронизация
 
Asynchrony and coroutines
Asynchrony and coroutinesAsynchrony and coroutines
Asynchrony and coroutines
 
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
Многопоточность, работа с сетью (Lecture 12 – multithreading, network)
 
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
 
iPhone Unit Testing (Google tool Box)
iPhone Unit Testing (Google tool Box)iPhone Unit Testing (Google tool Box)
iPhone Unit Testing (Google tool Box)
 
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
ПВТ - осень 2014 - Лекция 7. Многопоточное программирование без блокировок. М...
 
Mike ponomarenko java17-fork-v1.2
Mike ponomarenko java17-fork-v1.2Mike ponomarenko java17-fork-v1.2
Mike ponomarenko java17-fork-v1.2
 
Асинхронный JavaScript
Асинхронный JavaScriptАсинхронный JavaScript
Асинхронный JavaScript
 
Распространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложенийРаспространённые ошибки оценки производительности .NET-приложений
Распространённые ошибки оценки производительности .NET-приложений
 
C sharp deep dive
C sharp deep diveC sharp deep dive
C sharp deep dive
 
C# Deep Dive
C# Deep DiveC# Deep Dive
C# Deep Dive
 
OpenStack - Python Project with 12 Million Lines of code (RUS, Moscow Python ...
OpenStack - Python Project with 12 Million Lines of code (RUS, Moscow Python ...OpenStack - Python Project with 12 Million Lines of code (RUS, Moscow Python ...
OpenStack - Python Project with 12 Million Lines of code (RUS, Moscow Python ...
 
Froglogic Squish
Froglogic Squish Froglogic Squish
Froglogic Squish
 
Lec 14
Lec 14Lec 14
Lec 14
 
Приемочные тесты на огурце
Приемочные тесты на огурцеПриемочные тесты на огурце
Приемочные тесты на огурце
 

More from Sergey Teplyakov (6)

Void safety on Kiev ALT.NET
Void safety on Kiev ALT.NETVoid safety on Kiev ALT.NET
Void safety on Kiev ALT.NET
 
MS SWIT 2013 Design for Testability
MS SWIT 2013 Design for TestabilityMS SWIT 2013 Design for Testability
MS SWIT 2013 Design for Testability
 
Design by Contract basics
Design by Contract basicsDesign by Contract basics
Design by Contract basics
 
Visual studio toolbox
Visual studio toolboxVisual studio toolbox
Visual studio toolbox
 
Luxoft async.net
Luxoft async.netLuxoft async.net
Luxoft async.net
 
Reactive extensions
Reactive extensionsReactive extensions
Reactive extensions
 

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

Editor's Notes

  1. Первый слайд всего курса.
  2. Просто для того, чтобы с чего-нибудь начать разговор и подойти к сегодняшней теме я бы хотел немного напомнить историю развития платформы .NET и языка C# . Это даст нам понять то, как же мы докатились до такой жизни. В целом, нас интересует два последних релиза языка C# , которые и дали основной толчок асинхронному программированию на платформе .NET . И да, вам не послышалось и я не оговорился, именно два последних релиза сделали асинхронное программирование таким, каким мы его знаем сегодня, а не один последний релиз. В C# 4.0 ( а точнее в .NET Framework 4.0) появилась TPL , а в C# 5.0 (и .NET 4.5 ) эта модель асинхронного программирования стала повсеместной; и не последнюю роль в этом вопросе сыграли новые возможности языков C# и VB . NET . Давайте посмотрим, к чему же мы стремились.
  3. С одной стороны, асинхронное программирование на платформе .NET существовало с самой первой ее версии (в виде так называемой Asynchronous Programming Model ), а с другой стороны асинхронное программирование всегда было на порядок сложнее с точки зрения реализации, отладки и сопровождения, по сравнению с синхронной версией. Основная же цель новых «асинхронных» возможностей языка C# была направлена на «унификацию» синхронного и асинхронного программирования. Решить проблему асинхронности путем добавления пары ключевых слов в тело и заголовок методов, чтобы сделать их асинхронными. И это просто прекрасно, но сразу же после выхода этого дела в свет стало ясно, что у этой простоты есть своя цена! На самом деле, я могу
  4. TODO: выделить ключевые слова и Async , чтобы изменения были более видны
  5. Главная цель моего выступления заключается в том, чтобы немного сместить акцент с языковых конструкций, которые появлись в C# и VB с выходом VS2012 . Разобраться с новыми ключевыми словами не требует больших усилий, однако для написания нормального асинхронного кода все равно нужно понимать, что происходит внутри. О новых языковых возможностях не рассказывал и не писал только ленивый. В любой новой книге по языку C# , в любом выступлении на конференции об этом говорится. Но уже сейчас становится понятно, что та простота, которой так хотели добиться разработчики обладает и негативной стороной. Единственной сессией на MVP саммите в этом году было выступление Стивена Тауба и Лушиана Вишика о проблемах async void методах. Это первый такой звоночек, который говорит, что слишком многие относятся к новым возможностям слишком уж легкомысленно. Поэтому сегодня я хочу дать основные понятия и концепции, которые стоит изучить более подробно, чтобы стать асинхронным гуру!
  6. Абстракции текут и чтобы понимать что-то нам нужно разбираться на один уровень абстракции ниже!
  7. Обязательно сказать и продумать про разные типы приложений!!
  8. Когда речь заходит за UI потоки, то любой join асинхронной операции может привести к deadlock -у. В этом случае работает следующее правило: если вы начали использовать асинхронные операции, то их следует продолжать использование, а не ожидать их завершения (явно или неявно).
  9. Что будет в этом случае? Будет ли проброшено исключение первой задачи, второй задачи, обеих задач в виде AggregateException ?
  10. Очень печально, но в данном случае наружу вылетит лишь первое из возникших исключений! Я так и не смог добиться получения наружу обоих исключений!!
  11. 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
  12. Найти рисунок и цитату типа «тяп-ляп и в продакшн»