450 likes | 535 Views
Demystifying the .NET Asynchronous Programming Landscape. Bart J.F. De Smet blogs.bartdesmet.net/bart bartde@microsoft.com. It’s All About Time!. What’s asynchrony ? Greek origin a (not) syn (together with) chronos (time) Multiple parties evolving in time independently
E N D
Demystifying the .NET Asynchronous Programming Landscape Bart J.F. De Smet blogs.bartdesmet.net/bart bartde@microsoft.com
It’s All About Time! • What’s asynchrony? • Greek origin • a (not) • syn(together with) • chronos(time) • Multiple parties evolving in time independently • Not being blocked • Related concepts • Concurrency • Order in which multiple tasks execute is not determined • Parallelism • True simultaneous execution (e.g. multicore)
It’s a Jungle Out There! Reactive Events triggered Packetreceived Your Program Here I/O completed Callbacks Events
Nobody Likes to be Blocked • A connected world with I/O • Network sockets • Web services • Instant messaging • Don’t block the UI thread! • PostMessage • Control.Invoke • Dispatcher.BeginInvoke • Asynchrony in frameworks • Silverlight • Windows Phone 7 • AJAX Language support?
From the Bottom Up Hardware based on asynchrony… Programming model?
Abstractions in the .NET Framework Spot the defects using System; using System.IO; classProgram { staticvoid Main() { var buffer = newbyte[4 * 1024 * 1024 /* 4MB */]; using (varfs = File.OpenRead(@“c:\temp\sample.big”)) { fs.BeginRead(buffer, 0, buffer.Length, iar => { // Process results in buffer }, null); } } } Lifetime issues? Callback using a lambda expression Lack of closures in C# 1.0 Need EndRead?
Abstractions in the .NET Framework • Asynchronous Methods • Event-Based Asynchronous Pattern • BackgroundWorker Component IAsyncResultBeginRead(…, AsyncCallback callback, object state); intEndRead(IAsyncResult result); Use of callbackfunctions voidDownloadAsync(…); event DownloadCompletedEventHandlerDownloadCompleted; voidRunWorkerAsync(); voidReportProgress(intpercentProgress); event DoWorkEventHandlerDoWork; event ProgressChangedEventHandlerProgressChanged; event RunWorkerCompletedEventHandlerRunWorkerCompleted; Asynchronous is not unlike event-driven
The Task Parallel Library in .NET 4 True parallelism has become reality Can you keep the cores busy? Gordon Moore
Essential TPL Concepts – Task<T> • Representation of a computation • Also known as a “future” • Cheaper than threads • Continuations can be hooked up • Also known as “continuation passing style” (CPS) Code runs on the CLR’s task pool Task<int> x = Task<int>.Factory.StartNew(() => { // (Long-running) computation of the result. }); x.ContinueWith(x2 => { // Code for the continuation after x completes, // with x2 an alias for the original task. }); Continuations allow for sequencing Your application logic ends up inside out
Continuations for Dummies Returns abyte[] varreport = Task.Factory.StartNew(() => GetFileData()) Receives aTask<byte[]> Data available in byte[] Data Flow Pipeline What about errors? .ContinueWith(x => Analyze(x.Result)) Returns adouble[] Receives aTask<double[]> .ContinueWith(y => Summarize(y.Result));
Language Support for Asynchronous Programming – F# letprocessAsync i = async { use stream = File.OpenRead(sprintf"Image%d.tmp" i) let! pixels = stream.AsyncRead(numPixels) let pixels' = transform pixels i use out = File.OpenWrite(sprintf"Image%d.done" i) do!out.AsyncWrite(pixels') } letprocessAsyncDemo = printfn"async demo..." let tasks = [ for i in 1 .. numImages -> processAsync i ] Async.RunSynchronously (Async.Parallel tasks) |> ignore printfn"Done!" Compiler Transformation stream.Read(numPixels, pixels -> letpixels' = transform pixels i use out = File.OpenWrite(sprintf"Image%d.done" i) do! out.AsyncWrite(pixels') )
(Asynchronous) Workflows in F# • General-purpose language feature introduced by F# • Based on theory of monads • More exhaustive compared to LINQ in C# and VB • Overloadable meaning for specific keywords • Continuation passing style • Synchronous: ‘a -> ‘b • Asynchronous: ‘a -> (‘b -> unit) -> unit • In C# style: Action<T, Action<R>> • Core concept: async{ /* code */ } • Syntactic sugar for keywords inside block • E.g. let!, do!, use! Continuation function receives result (~ ContinueWith)
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } Message Pump UI Thread
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); }
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); }
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); }
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } t1
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } t1 t2
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } t1 t2
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } t1 t2
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } t1 t2
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } t1 t2
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } t1 t2
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } t1 t2
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } t1 t2
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } t1 t2
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } t1 t2
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } t1 t2
Asynchronous Control Flow async voidDoWorkAsync() { var t1 = ProcessFeedAsync("www.acme.com/rss"); var t2 = ProcessFeedAsync("www.xyznews.com/rss"); awaitTask.WhenAll(t1, t2); DisplayMessage("Done"); } asyncTaskProcessFeedAsync(stringurl) { var text = awaitDownloadFeedAsync(url); var doc = ParseFeedIntoDoc(text); awaitSaveDocAsync(doc); ProcessLog.WriteEntry(url); } t1 t2
Events Are All Around Us GPS RSS feeds Stock tickers Social media UI events Server management
Event Processing Systems Way simpler with Rx Rx is a library for composing asynchronous and event-basedprograms using observable sequences. Queries! LINQ! • .NET 3.5 SP1 and 4.0 • Silverlight 3, 4, and 5 • XNA 4.0 for Xbox 360 • Windows Phone 7 • JavaScript (RxJS) Download at MSDN Data Developer Centeror use NuGet
Push-Based Data Retrieval Application MoveNext Got next? OnNext Interactive Reactive Have next! Environment IObservable<T> IObserver<T> IEnumerable<T> IEnumerator<T>
Event Programming Interfaces Both interfaces ship in the .NET 4 BCL interface IObservable<out T> { IDisposable Subscribe(IObserver<T> observer);} interfaceIObserver<in T> { voidOnNext(T value); voidOnError(Exception ex); voidOnCompleted(); } Observers used to define callbacks In today’s word, errors are a given
Writing Rx Queries over Event Streams Importing.NET events as observables // IObservable<string> from TextChanged events varchanged = Observable.FromEventPattern(txt, "TextChanged"); varinput = (fromtext inchanged select((TextBox)text.Sender).Text); .DistinctUntilChanged() .Throttle(TimeSpan.FromSeconds(1)); // Bridge with the dictionary web service var svc = newDictServiceSoapClient();var lookup = Observable.FromAsyncPattern<string, DictionaryWord[]> (svc.BeginLookup, svc.EndLookup); // Retrieve results and hop from stream to stream var res = (from term in input selectlookup(term)) .Switch(); Bridging the async method pattern One stream per web service request
Asynchronous Data Processing Overview # IObservable<T> IEnumerable<T> res = fromx inxsfrom y inq(x) …; Multiple values (*) Functionalstyle code res.Subscribe(x => … foreach(varzinres) … Composition on query expressions Task<T> Func<T> y = f(x); y = awaitg(x); Imperativestyle code Single value (1) Invocationexpressions Awaitexpressions Sequencing through statements Synchronous Asynchronous
Summary • Asynchrony is everywhere • Emergence of async-only APIs • Windows Phone, Silverlight, JavaScript • Don’t block the UI • Have to deal with latency • Call to action • Learn about Task<T> • Download the Async CTP • http://msdn.com/vstudio/async • Download Reactive Extensions (Rx) • http://msdn.com/data/gg577609
Stay up to date with MSDN Belux • Register for our newsletters and stay up to date:http://www.msdn-newsletters.be • Technical updates • Event announcements and registration • Top downloads • Follow our bloghttp://blogs.msdn.com/belux • Join us on Facebookhttp://www.facebook.com/msdnbehttp://www.facebook.com/msdnbelux • LinkedIn: http://linkd.in/msdnbelux/ • Twitter: @msdnbelux DownloadMSDN/TechNet Desktop Gadgethttp://bit.ly/msdntngadget
TechDays 2011 On-Demand • Watchthis session on-demand via Channel9http://channel9.msdn.com/belux • Download to your favorite MP3 or video player • Get access to slides and recommended resources by the speakers