Asynchronous programming in .NET (UA)

42
Асинхронне програмування в .NET Олександр Павлишак травень 2012

Transcript of Asynchronous programming in .NET (UA)

Page 1: Asynchronous programming in .NET (UA)

Асинхронне програмування в .NET

Олександр Павлишак

травень 2012

Page 2: Asynchronous programming in .NET (UA)

Для кого

Початківці

Ідея асинхронності

Базові техніки

Досвідчені

Поточний стан справ

Нові бібліотеки та підходи

Структуризація, порівняння

Outside .NET

Нові ідеї, розширення світогляду

Page 3: Asynchronous programming in .NET (UA)

План

Асинхронність intro

Asynchronous Programming Model (APM)

Tasks (Task Parallel Library)

Reactive Extensions (Rx)

C# 5.0 async

Page 4: Asynchronous programming in .NET (UA)

Асинхронність

– Ініціювати виконання операції

– Не чекати поки операція закінчиться,

– а одразу повернути виконання

– Продовжувати займатись іншими справами

– Могти скасувати операцію

– Отримати сповіщення про результат операції (успішний/неуспішний)(callback)

== відсутність блокування

Page 5: Asynchronous programming in .NET (UA)

На клієнті

UI потік не можна блокувати

Типові асинхронні операції:

– Запити до серверів (веб, БД, sockets) – IO bound

– Читання/запис на диск – IO bound

– Довготривалі обчислення – CPU bound

Основна незручність:

– результат асинхронної операції повинен бути оброблений в UI потоці

Основна мета – responsiveness

Page 6: Asynchronous programming in .NET (UA)

Бажане функціонування UI потоку

– Багато дрібних подій, виконання кожної з яких швидко завершується

– Події – message pump events + async operations callbacks

– Новим подіям не приходиться довго чекати на початок виконання

Page 7: Asynchronous programming in .NET (UA)

Hardware працює асинхронно

CPU не блокується на операціях з пам’яттю, диском, мережевим адаптером

Всі IO пристрої володіють затримкою (latency)

Непередбачуваною

Підтримка OS: Completion ports

Недолік –програмна модель досить складна

O RLY?

Page 8: Asynchronous programming in .NET (UA)

IO-bound задачі можуть виконуватись фоново (на апаратному рівні)

Як наслідок:

Не потрібні лишні потоки програми з логікою обробки результатів IO

Цим може займатись UI потік,

якщо ця обробка швидка.

Потрібна зручна абстракціяCompletion ports занадто низькорівневі

Плюс є ще CPU-bound задачі

Page 9: Asynchronous programming in .NET (UA)

На сервері

Задача – обробляти багато клієнтських запитів одночасно

(concurrency)

Модель IIS + ASP.NET: 1 request – 1 thread1000 запитів – 1000 потоків

1000 запитів – 30 потоків + 970 запитів в черзі

Оптимальна кількість потоків = кількості CPU

Неефективне використання ресурсів:Більшість часу потоки чекають на IO

А коли прокидаються, конкурують за CPU

Основна мета – масштабованість (scalability)

Page 10: Asynchronous programming in .NET (UA)

Responsiveness and scalabilityдві мети асинхронного програмування

Callbacksзасіб реалізації, який володіє проблеми :(

Потрібне розширення абстракції callback’a,а також кращі абстракції замість callback’ів

Page 11: Asynchronous programming in .NET (UA)

Простий випадок: виконуємо одну операцію асинхронно(лише happy path)

Demo:

UI (load/save values)APM (Asynchronous Programming Model)

Альтернативи: окремий потік + UI через dispatcher

ASP.NET (call web service)APM

приклади тут

Page 12: Asynchronous programming in .NET (UA)

stream.BeginRead(buffer, 0, buffer.Length, asyncResult =>{

context.Post(_ =>{

try{

stream.EndRead(asyncResult);stream.Dispose();Input = Encoding.ASCII.GetString(buffer);

}catch{

Input = "Error!!!";}finally{

DisplayLoadCompletedNotification();}

}, null);}, null);

Can throw

Execute in UI thread

Does not block

Does not block here

Captured in closure

“Awesomeness” of callbacks

Page 13: Asynchronous programming in .NET (UA)

Все ускладнюється

Обробка помилок

Cancellation

Запуск багатьох операцій послідовно

Запуск декількох операцій паралельно+ після закінчення сповістити користувача

Координація операційпісля закінчення двох викликів запустити третій

...));}}}));

Wait, this is not LISP!

Page 14: Asynchronous programming in .NET (UA)

APM

Запуск: fileStream.BeginRead(…)

Callback: BeginRead(…, asyncResult => { … }, …)Викликає EndRead()

SynchronizationContext – щоб повернутись в UI потік

Результат: виклик EndRead()

Exceptions: виклик EndRead()try…catch навколо EndRead() всередині callback

Де:Thread from IO thread pool

Явне використання SynchronizationContext.Post()

Composition: :(

Page 15: Asynchronous programming in .NET (UA)

Futures and Promises

Розділення ініціювання операції від отримання результату

Func<>, Action<> – навпаки

Реалізація – Task<T>Обох понять, future and promise

Обох видів, IO-bound and CPU-bound

Block on Task.Result

Continuation with Task.ContinueWith()

Task.Result повідомляє про Exception

Page 16: Asynchronous programming in .NET (UA)

RestoreInput().ContinueWith(restoreInputTask =>

{try{

Input = restoreInputTask.Result;}catch{

Input = "Error!!!";}finally{

DisplayLoadCompletedNotification();}

}, TaskScheduler.FromCurrentSynchronizationContext());

Returns Task<string> Called when task completes

Does not block Rethrows

Where to execute continuation

Already started

In UI thread

Task returned by RestoreInput()

We can schedule several continuations

Page 17: Asynchronous programming in .NET (UA)

Task<string> RestoreInput(){

return Task.Factory.StartNew(() =>{

return File.ReadAllText("savedInput.txt");});

}

Returns started task

Runs in thread poolby default

Exception will be re-thrown in Task.Result

Can specify Scheduler

Page 18: Asynchronous programming in .NET (UA)

Запуск Task’ів

TaskFactory.FromAsync()Адаптація APM-моделі до Task-моделі

TaskFactory.StartNew(() => { return …; })Адаптація будь-якої моделі до Task

Вказується TaskScheduler

Вказується CancellationToken

Page 19: Asynchronous programming in .NET (UA)

Demo

Save/load values with TPL

Page 20: Asynchronous programming in .NET (UA)

Tasks

Запуск: TaskFactory.FromAsync()TaskFactory.StartNew()

Callback: Task.ContinueWith()Викликає Task.Result

Результат: Task.Result in continuationExceptions: виклик Task.Result

try…catch навколо Task.Result всередині callbackTask.Exception, Task.IsFaulted, Task.Status

Де:При запуску вказується TaskSchedulerВ ContinueWith() вказується TaskScheduler

Composition: ContinueWith(), WhenAll/Any()

Page 21: Asynchronous programming in .NET (UA)

Events

Корисна абстракція, не лише для UIFirst class (F#), Delegates (C#), GOF-style Observers

Single events: button click, request received

Event streams: mouse moves,key presses, stream of tweets

Події часто асинхронніПроблема – погано компонуються

Unless first class

Page 22: Asynchronous programming in .NET (UA)

Уявіть композицію

Швидкий пошук, фільтр

Page 23: Asynchronous programming in .NET (UA)

Уявіть композицію

По суті – серія подій OnTextChanged

Рядок повинен обрізатись – String.Trim()Tabs spaces; multiple spaces single space

Рядки із спец. символами повинні виключатись

Запуск пошуку – коли користувач перестане друкувати – throttling

Пошук лише значень, які відрізняються(послідовних) – distinct

Відображення результату останнього пошуку а не того, який прийшов найпізніше

Запис в історію пошуку

IFs, IFs, IFs

Timer

Shared mutable var

More mutable state

Multiple subscribers

Page 24: Asynchronous programming in .NET (UA)

Reactive Extensions

Серія OnTextChanged = stream of TextBox.Texts

Звучить як... IEnumerable<string>?Pull-based: T MoveNext(void)

IObservable<string>!Push-based: void OnNext(T)

Functional Programming! Monads! Composition! Pure functions! Say No to Mutable State! Support cancer research!

Lambda

Page 25: Asynchronous programming in .NET (UA)

Observer ≈≈ Iterator

interface IEnumerator<out T>{

T Current { get; }

bool MoveNext(void);}

interface IObserver<in T>

{

void OnNext(T);

void OnError(Exception);

void OnCompleted();

}

interface X<out T>{

T|Exception X(void)

bool X(void);}

interface X<in T>

{

void X(T);

void X(Exception);

void X(bool);

}

Page 26: Asynchronous programming in .NET (UA)

Observer ≈≈ Iterator

interface IObservable<out T>

{

IDisposable Subscribe(Observer<T>);

}

interface IEnumerable<out T>

{

IEnumerator<T> GetEnumerator(void);

}

textChanges.Select(s => s.Trim()).Where(s => s != "").Subscribe(onNext:

s => Console.WriteLine(s));

IObservable<string>IObservable<string>

Runs on each received string

Can also pass onError, onCompleted

Returns IDisposable for un-subscription

Page 27: Asynchronous programming in .NET (UA)

Reactive Extensions (Rx)

A library for composing asynchronous and event-based programs using observable

sequences and LINQ-style query operators.

Rx = Observables + LINQ + Schedulers

Official site

Page 28: Asynchronous programming in .NET (UA)

Demo

Single event – Save/Load settings

Event stream – TextBox.Text changes

Page 29: Asynchronous programming in .NET (UA)

Rx

Запуск: багато шляхів, включаючи:Observable.Return(), Observable.FromAsyncPattern()

Callback: IObserver.OnNext()IObservable.Subscribe(item => { … })

Результат: IObserver.OnNext()

Exceptions:IObserver.OnError(Exception)

Catch(), Finally(), OnErrorResumeNext() combinators

Де:ObserveOn(IScheduler)

Composition: широкий набір комбінаторів, LINQ

Page 30: Asynchronous programming in .NET (UA)

Rx – функціональний шлях вирішення проблем з асинхронністю

та concurrency

Як щодо імперативного стилю?

Monads! Composition! Purity!

Page 31: Asynchronous programming in .NET (UA)

Імперативний стиль

Наскільки sync код відрізняється від async?

Суттєво відрізняється!

хіба що ви програмували у функціональному стилі з самого початку

Як конвертувати sync код в async?

Перетворювати в continuations – CPS

Як бути з while/for/foreach?

try…catch? finally? using() {…}?

hint hint :)

Page 32: Asynchronous programming in .NET (UA)

Після перетворення

Перетворений код буде

– Рекурсивний (tail recursion, anyone?)

– Реалізовувати машину станів (goto is back!)

Хороша новина: така трансформація є механічна

Compiler can do it automagicallyforeach

yield return

Pattern-based

foreach over non-IEnumerable

Page 33: Asynchronous programming in .NET (UA)

Імперативний sync код

try{

DisplayLoadingInProgressNotification();Input = RestoreInput();

}catch{

Input = "Error!!!";}finally{

DisplayLoadCompletedNotification();}

Page 34: Asynchronous programming in .NET (UA)

async

try{

DisplayLoadingInProgressNotification();Input = await RestoreInput();

}catch{

Input = "Error!!!";}finally{

DisplayLoadCompletedNotification();}

Page 35: Asynchronous programming in .NET (UA)

Ще приклад: цикл

try{

DisplayLoadingInProgressNotification();foreach (var textBox in InputTextBoxes){

try{

textBox.Text = RestoreInput(GetFileName(textBox));

}catch{ textBox.Text = "Error!!!"; }

}}finally{ DisplayLoadCompletedNotification(); }

Page 36: Asynchronous programming in .NET (UA)

async з циклом

try{

DisplayLoadingInProgressNotification();foreach (var textBox in InputTextBoxes){

try{

textBox.Text = await RestoreInput(GetFileName(textBox));

}catch{ textBox.Text = "Error!!!"; }

}}finally{ DisplayLoadCompletedNotification(); }

Page 37: Asynchronous programming in .NET (UA)

await non-thread-pool Task

async Task<string> RestoreInput(){

using (var reader = File.OpenText("savedInput.txt")){

var result = await reader.ReadToEndAsync();Debug.WriteLine("Input restored from file.");return result;

}}

Page 38: Asynchronous programming in .NET (UA)

await thread-pool Tasks

if (File.Exists(fileName))

return await Task.Run(() =>

{

return File.ReadAllText(fileName);

});

else

return String.Empty;

Page 39: Asynchronous programming in .NET (UA)

Demo

async save/load value

async save/load multiple values in sequence

async save/load multiple values in parallel

Page 40: Asynchronous programming in .NET (UA)

async, await

Запуск: call async APIReturning Task, WinRT or any awaitable

Callback: код, який слідує після awaitабо Task.ContinueWith()

Результат: await

Exceptions: await

Де: в поточному SynchronizationContextМожна також заборонити context capturing;

Composition: імперативний кодТакож Tasks

Page 41: Asynchronous programming in .NET (UA)

APM, Tasks, Rx, asyncAPM

- Callback model

- Композиція складна

Tasks+/- Callbacks

+ Краща композиція, обробка помилок, cancellation

Rx++ Композиція, обробка помилок та cancellationу функціональному стилі

- Learning curve

async+/- Композиція, обробка помилок в імперативному стилі

+ Конвертується в Tasks

Page 42: Asynchronous programming in .NET (UA)

Дякую за увагу!

TPL Home Team Blog Free book Other book

Reactive Extensions Home C9-Videos Intro

async Home Spec Jon Skeet InfoQ WinRT Deep

Презентація slideshare.net/opavlyshak

Приклади github.com/opavlyshak/dotNet-async-demos

@pavlyshak

[email protected]