Его Высочество Async

Page 1

Его Высочество 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!


Что будет в этом случае? Захватываем Sync Context

private async Task<int> FooAsync() { Возвращает await Task.Delay(10); управление! return 42; Ожидает освобождения } UI потока private void btn_Click(object sender, EventArgs e) { label.Text = FooAsync().Result.ToString(); } Ожидает завершения асинхронной операции


“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"); Получим “E1”? }); // t2 тоже "падает" Task<int> t2 = Task<int>.Factory.StartNew(() => { throw new Exception("E2"); Получим “E2”? });

int r1 = await t1; int r2 = await t2; }

Получим 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) { Результирующая задача перейдет в Faulted состояние! if (buffer == null) throw new ArgumentNullException("buffer"); // Реализация асинхронного чтения return 42; }

Зачем заморачиваться?

• Синхронное исключение означает «баг» в вызывающем коде. • «Поломанная» задача означает баг в реализации!


Корректная реализация 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 • Sergey.Teplyakov@gmail.com • 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 class CustomProvider { public static void ExecuteOperation(Operation operationId, Action<CustomData> action, Action<Exception> func); } public Task<CustomData> GetCustomDataAsync() { var tcs = new TaskCompletionSource<CustomData>(); // Начинаем асинхронную операцию, и передаем // два специализированных делегата CustomProvider.ExecuteOperation(Operation.ReadCustomer, data => tcs.SetResult(data), e => tcs.SetException(e)); return tcs.Task; }


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.