About Those Python Async Concurrent Frameworks - Fantix @ OSTC 2014
Его Высочество Async
-
Upload
luxoft-training -
Category
Documents
-
view
242 -
download
1
description
Transcript of Его Высочество Async
Его Высочество Async
Сергей Тепляков, Visual C# MVP .NET Architect at Luxoft
SergeyTeplyakov.blogspot.com
Эволюция языка C#
Sync vs Async
Synchronous Perform something here and now.
I’ll regain control to execute something else
when it’s done.
Asynchronous
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(); } }
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(); } }
Если вы думаете, что асинхронное программирование стало проще!
Копайте в глубь! Все нетривиальные абстракции дырявы Джоэл Спольски «Закон дырявых абстракций»
Вы должны понимать как минимум на один уровень абстракции ниже того уровня, на котором вы кодируете Ли Кэмпбел (Lee Campbell)
Async/await – лишь вершина
Synchronization Context
• Некоторые типы приложений налагают ограничения на «потоковую» модель
• Control.Invoke/BeginInvoke
• Dispatcher.Invoke/BeginInvoke
• Контекст синхронизации «прячет» эти детали за абстрактным интерфейсом
• Контекст нужен для «маршалинга» управления из одного потока в другой (*)
• Контексты повсюду!
Зачем мне это? Я же программирую на C# 5.0!
Что будет в этом случае?
private async Task<int> FooAsync() { await Task.Delay(10); return 42; } private void btn_Click(object sender, EventArgs e) { label.Text = FooAsync().Result.ToString(); }
Ожидает освобождения UI потока
Ожидает завершения асинхронной операции
Захватываем Sync Context
Возвращает управление!
“Sync over Async” + UI == Deadlock!
Решение private async Task<int> FooAsync() { await Task.Delay(10); return 42; } private async void btn_Click(object sender, EventArgs e) { label.Text = (await FooAsync()).ToString(); }
Обработка нескольких исключений 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!
Unobserved Exceptions
• Событие TaskScheduler.UnobservedException
• Генерируется финализатором
• Не вызывается при обращении к
• Result
• Exception
• Вызове Wait
• Поведение зависит от версии .NET Framework
• .NET 4.5 – «умалчивается» (*)
• .NET 4.0 – «ломает» приложение
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!!!"); } }
“Решение” 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!!!!
И как это дело ловить? 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) {}
Где вылетит ошибка? var ms = new MemoryStream(); // Здесь? Task<int> task = ms.ReadAsync(null, 0, 42); // Или здесь? int result = task.Result;
• Является исключение «синхронным» или «асинхронным»?
«Наивная» реализация public static async Task<int> ReadAsync(byte[] buffer) { if (buffer == null) throw new ArgumentNullException("buffer"); // Реализация асинхронного чтения return 42; }
Результирующая задача перейдет в Faulted состояние!
• Синхронное исключение означает «баг» в вызывающем коде.
• «Поломанная» задача означает баг в реализации!
Зачем заморачиваться?
Корректная реализация
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; }
Синхронная проверка «предусловий»
Сколько же тут всего…
• Влияние TAP на дизайн приложения!
• Обработка исключений • Unobserved exceptions
• Bugs vs Task Faults
• Гранулярность асинхронных операций
• Testability
• Work stealing
• Async Programming Guidelines • Avoid “async void”
• Avoid async lambdas
• Consider performance impact
• Avoid “Sync over Async”
• Avoid “Async over Sync”
• Consider using ConfigureAwait
Вот этого не надо
- Как вы пишите софт? - Бац-бац и в продакшн (с).
- Как из синхронного приложения сделать асинхронное? - Async/await и готово!
Его высочество Async …
не так прост, как кажется;)
Вопросы?
Спасибо за внимание
• Сергей Тепляков, Visual C# MVP
• .NET Architect at Luxoft
• http://sergeyteplyakov.blogspot.com/
Что думает по этому поводу 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.
Task vs Observables
TaskCompletionSource фасад к старому асинхронному
миру!
Пример
public Task<CustomData> GetCustomDataAsync() { var tcs = new TaskCompletionSource<CustomData>(); // Начинаем асинхронную операцию, и передаем // два специализированных делегата CustomProvider.ExecuteOperation(Operation.ReadCustomer, data => tcs.SetResult(data), e => tcs.SetException(e)); return tcs.Task; }
public class CustomProvider { public static void ExecuteOperation(Operation operationId, Action<CustomData> action, Action<Exception> func); }