Тонкости асинхронного программирования
TRANSCRIPT
1 © L
uxof
t Tra
inin
g 20
13
06 июля 2013
Тонкости асинхронного программирования
Dev Labs
2 © L
uxof
t Tra
inin
g 20
13
Эволюция языка C#
3 © L
uxof
t Tra
inin
g 20
13
Sync vs Async
SynchronousPerform something here and now.I’ll regain control to execute something else when it’s done.
4 © L
uxof
t Tra
inin
g 20
13
Sync vs Async
Caller Srv
Foo
42
Caller Srv
Operation finishedResult: 42
FooAsync
Operation Started
Bckgn
Starting background operation
Notifies
t
t
t0
Sync vs Async
5 © L
uxof
t Tra
inin
g 20
13
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 © L
uxof
t Tra
inin
g 20
13
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 © L
uxof
t Tra
inin
g 20
13
Demo – sync 2 async
8 © L
uxof
t Tra
inin
g 20
13
Если вы думаете, что асинхронное программирование
стало проще!
9 © L
uxof
t Tra
inin
g 20
13
Копайте в глубь!
Все нетривиальные абстракции дырявыДжоэл Спольски «Закон дырявых абстракций»
Вы должны понимать как минимум на один уровень абстракции ниже того уровня, на котором вы кодируетеЛи Кэмпбел (Lee Campbell)
10 © L
uxof
t Tra
inin
g 20
13
Async/await – лишь вершина
11 © L
uxof
t Tra
inin
g 20
13
Synchronization Context
Некоторые типы приложений налагают ограничения на «потоковую» модель
Control.Invoke/BeginInvoke
Dispatcher.Invoke/BeginInvoke
Контекст синхронизации «прячет» эти детали за абстрактным интерфейсом
Контекст нужен для «маршалинга» управления из одного потока в другой (*)
Контексты повсюду!
12 © L
uxof
t Tra
inin
g 20
13
Зачем мне это?Я же программирую на C#
5.0!
13 © L
uxof
t Tra
inin
g 20
13
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 © L
uxof
t Tra
inin
g 20
13
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 © L
uxof
t Tra
inin
g 20
13
Другими словами…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 © L
uxof
t Tra
inin
g 20
13
“Sync over Async” + UI == Deadlock!
18 © L
uxof
t Tra
inin
g 20
13
Решение
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 © L
uxof
t Tra
inin
g 20
13
Где вылетит ошибка?
var ms = new MemoryStream();
// Здесь? Task<int> task = ms.ReadAsync(null, 0, 42);
// Или здесь? int result = task.Result;
• Является исключение «синхронным» или «асинхронным»?
20 © L
uxof
t Tra
inin
g 20
13
«Наивная» реализация
public static async Task<int> ReadAsync(byte[] buffer) { if (buffer == null) throw new ArgumentNullException("buffer");
// Реализация асинхронного чтения return 42; }
Результирующая задача перейдет в Faulted
состояние!
• Синхронное исключение означает «баг» в вызывающем коде.
• «Поломанная» задача означает баг в реализации!
Зачем заморачиваться?
21 © L
uxof
t Tra
inin
g 20
13
Корректная реализация
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 © L
uxof
t Tra
inin
g 20
13
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 © L
uxof
t Tra
inin
g 20
13
Обработка нескольких исключений
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?UnobservedTaskExcep
tion!
24 © L
uxof
t Tra
inin
g 20
13
Unobserved Exceptions
Событие TaskScheduler.UnobservedException
Генерируется финализатором
Не вызывается при обращении к
Result
Exception
Вызове Wait
Поведение зависит от версии .NET Framework
.NET 4.5 – «умалчивается» (*)
.NET 4.0 – «ломает» приложение
25 © L
uxof
t Tra
inin
g 20
13
“Решение”
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 © L
uxof
t Tra
inin
g 20
13
Структура исключений
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 © L
uxof
t Tra
inin
g 20
13
И как это дело ловить?
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 © L
uxof
t Tra
inin
g 20
13
Асинхронные методы
Типы возвращаемого значения асинхронного метода:
async void FooAasync() – Fire and Forget (*)
async Task FooAsync() – (void Foo())
async Task<T> FooAsync() – (T Foo())
29 © L
uxof
t Tra
inin
g 20
13
Где вылетит ошибка?
private static async void FooAsync(){ throw new Exception("Ooops!");}
It Depends!
30 © L
uxof
t Tra
inin
g 20
13
Demo – async void exceptions
31 © L
uxof
t Tra
inin
g 20
13
Задача: убедиться, что метод генерирует исключение!
32 © L
uxof
t Tra
inin
g 20
13
Naïve Approachpublic 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 © L
uxof
t Tra
inin
g 20
13
Рабочий вариант![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 © L
uxof
t Tra
inin
g 20
13
Async Guidelines
Async void – это операции вида “fire-and-forget”
Вызывающий код не может узнать о завершении асинхронного метода
Вызывающий код не может обработать исключения(вместо этого они попадут в цикл обработки UI сообщений или «уронят» приложение!)
Используйте async void только для обработчиков событий самого высокого уровня.
Используйте возвращаемые значения!
Осторожнее с асинхронными лямбда-выражениями!
35 © L
uxof
t Tra
inin
g 20
13
Сколько же тут всего…
Влияние TAP на дизайн приложения!
Обработка исключений Unobserved exceptions
Bugs vs Task Faults
Гранулярность асинхронных операций
Testability
Work stealing
36 © L
uxof
t Tra
inin
g 20
13
Вот этого не надо
- Как вы пишите софт?- Бац-бац и в продакшн (с).
- Как из синхронного приложения сделать асинхронное?- Async/await и готово!
37 © L
uxof
t Tra
inin
g 20
13
Его высочество Async …
не так прост, как кажется;)
38 © L
uxof
t Tra
inin
g 20
13
Что думает по этому поводу 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 © L
uxof
t Tra
inin
g 20
13
Дополнительные ссылки
pfxteam blog
C# Async Tips and Tricks Part 2: Async Void
MVP Summit presentation on async
Знакомство с асинхронными операциями в C# 5
40 © L
uxof
t Tra
inin
g 20
13
Благодарю за внимание!
Вопросы?
41 © L
uxof
t Tra
inin
g 20
13
IntHRLuxtown
Информация об учебном центре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