F# Asynchronous and Reactive Programming Don Syme, Microsoft Research with help from Nikolaj Bjorner, Laurent le Brun, Luke Hoban, Brian McNamara, James.

Slides:



Advertisements
Similar presentations
Introduction to Concurrency in F# Joey Dodds. F# F# Warmup F# async basics async let! examples Continuations Events.
Advertisements

Parallel Extensions to the.NET Framework Daniel Moth Microsoft
Ch. 7 Process Synchronization (1/2) I Background F Producer - Consumer process :  Compiler, Assembler, Loader, · · · · · · F Bounded buffer.
CSE 1302 Lecture 21 Exception Handling and Parallel Programming Richard Gesick.
Lecture 4 Thread Concepts. Thread Definition A thread is a lightweight process (LWP) which accesses a shared address space provided by by the parent process.
Languages for Dynamic Web Documents
Сошников Дмитрий Валерьевич к.ф.-м.н., доцент Майкрософт Россия, департамент стратегических технологий Факультет инноваций и высоких.
Concurrency CS 510: Programming Languages David Walker.
An introduction to F# (part 2) Bogdan Brinzarea-Iamandi Banca Romaneasca 25 February 2010.
Why is Microsoft investing in Functional Programming? Don Syme With thanks to Leon Bambrick, Chris Smith and the puppies All opinions are those of the.
CSE S. Tanimoto Syntax and Types 1 Representation, Syntax, Paradigms, Types Representation Formal Syntax Paradigms Data Types Type Inference.
F# Shiva Srivastava David He Peter Bingel. Overview F# (pronounced "F sharp") is a functional and object oriented programming language for the Microsoft.NET.
1 Thread Pools. 2 What’s A Thread Pool? A programming technique which we will use. A collection of threads that are created once (e.g. when server starts).
Platforms and tools for Web Services and Mobile Applications Introduction to C# Bent Thomsen Aalborg University 3rd and 4th of June 2004.
Multi-paradigm language Type inferred Just another.NET language Tools First-class language in VS2010* F# Interactive Window F# PowerPack F# = Fun.
CS252: Systems Programming Ninghui Li Final Exam Review.
Neal Stublen Practice Solution  Create a new solution  Add a WinForms project  Add a Class Library project  Reference the library.
 George Chrysanthakopoulos Software Architect Microsoft Corporation.
Networking Nasrullah. Input stream Most clients will use input streams that read data from the file system (FileInputStream), the network (getInputStream()/getInputStream()),
Modern Concurrency Abstractions for C# by Nick Benton, Luca Cardelli & C´EDRIC FOURNET Microsoft Research.
CSE 380 – Computer Game Programming Render Threading Portal, by Valve,
CSCI 6962: Server-side Design and Programming JDBC Database Programming.
NOTE: To change the image on this slide, select the picture and delete it. Then click the Pictures icon in the placeholder to insert your own image. WEB.
Session 1 - Introduction and Data Access Layer
 Ed Pinto PM Microsoft Corporation. Host “Dublin”(IIS/WAS + App Server Extensions) Microsoft ®.NET Workflow Service.exe Host “Dublin”(IIS/WAS + App.
1 Lecture 4: Threads Operating System Fall Contents Overview: Processes & Threads Benefits of Threads Thread State and Operations User Thread.
INTERPRETING IMPERATIVE PROGRAMMING LAGUAGES IN EXTENSIBLE STYLESHEET LANGUAGE TRANSFORMATIONS (XSLT) Authors: Ruhsan Onder Assoc.
UDI Tutorial & Driver Walk-Through Part 2 Kurt Gollhardt SCO Core OS Architect
Putting it all together: LINQ as an Example. The Problem: SQL in Code Programs often connect to database servers. Database servers only “speak” SQL. Programs.
Parallel Extensions A glimpse into the parallel universe By Eric De Carufel Microsoft.NET Solution Architect at Orckestra
File I/O 11_file_processing.ppt
Win32 Programming Lesson 10: Thread Scheduling and Priorities.
NOTE: To change the image on this slide, select the picture and delete it. Then click the Pictures icon in the placeholder to insert your own image. WEB.
About Me Microsoft MVP Intel Blogger TechEd Israel, TechEd Europe Expert C++ Book
1 (Worker Queues) cs What is a Thread Pool? A collection of threads that are created once (e.g. when a server starts) That is, no need to create.
High Productivity Computing: Taking HPC Mainstream Lee Grant Technical Solutions Professional High Performance Computing
Hibernate Persistence. What is Persistence Persist data to database or other storage.  In OO world, persistence means persist object to external storage.
Reactive pattern matching for F# Part of “Variations in F#” research project Tomáš Petříček, Charles University in Prague
Copyright ©2004 Virtusa Corporation | CONFIDENTIAL Windows Workflow Foundation Ruwan Wijesinghe.
ICS 313: Programming Language Theory Chapter 13: Concurrency.
Programovací jazyky F# a OCaml Chapter 6. Sequence expressions and computation expressions (aka monads)
© Janice Regan, CMPT 300, May CMPT 300 Introduction to Operating Systems Operating Systems Processes and Threads.
 In the java programming language, a keyword is one of 50 reserved words which have a predefined meaning in the language; because of this,
Today… “Hello World” ritual. Brief History of Java & How Java Works. Introduction to Java class structure. But first, next slide shows Java is No. 1 programming.
TAP into async programming
CSC 298 Streams and files.
Don Syme Research Architect Microsoft Session code: DEV306.
Patterns of Parallel Programming with.NET 4 Stephen Toub Principal Architect Parallel Computing Platform Microsoft Corporation
TOPICS WHAT YOU’LL LEAVE WITH WHO WILL BENEFIT FROM THIS TALK.NET developers: familiar with parallel programming support in Visual Studio 2010 and.NET.
C# Present and Future Marita Paletsou Software Engineer.
C# 5.0 Alex Davies 22 nd December What we will cover C# 5.0,.NET 4.5, Visual Studio 11 Caller Info Attributes Upgrade from synchronous to asynchronous.
pThread synchronization
1 Concurrency Abstractions in C#. Concurrency in C# CS 5204 – Fall, Motivation Concurrency critical factor in behavior/performance affects semantics.
 It is a pure oops language and a high level language.  It was developed at sun microsystems by James Gosling.
Module 9: Memory and Resource Management
Java Programming Language
Representation, Syntax, Paradigms, Types
Async or Parallel? No they aren’t the same thing!
The Client/Server Database Environment
12 Asynchronous Programming
F# for Parallel and Asynchronous Programming
Representation, Syntax, Paradigms, Types
Representation, Syntax, Paradigms, Types
Representation, Syntax, Paradigms, Types
Why Threads Are A Bad Idea (for most purposes)
CSE 451 Section 1/27/2000.
Why Threads Are A Bad Idea (for most purposes)
Why Threads Are A Bad Idea (for most purposes)
Server & Tools Business
Presentation transcript:

F# Asynchronous and Reactive Programming Don Syme, Microsoft Research with help from Nikolaj Bjorner, Laurent le Brun, Luke Hoban, Brian McNamara, James Margetson

Today A bit about F# Background: F# Monadic Syntax Asynchronous and Parallel Programming using F# workflows

The.NET Context XML Libraries Visual Studio Debuggers, Profilers GUI Libraries, etc. System.I/O System.Net etc. C#.NET Common Language Runtime Visual Basic Database Connection Libraries Graphics Libraries ML F#

F# as a Language Core ML Modules-as- values, functors OCaml F# “OCaml-Objects” and other extensions Core ML.NET Nominal Objects Other extensions + tools Similar core language

Pattern Matching F# has five primary syntactic categories – Expressions – Declarations – Types – Patterns – Computation Expressions (= Workflows = Monadic Syntax)

F# “Workflow” Syntax Monadic syntax added to F# aimed at: List/Sequence/Array comprehensions Database queries Asynchronous/Reactive Programming Probabilistic modelling Modalities (client/server) ≈≈ "monads", but rebranded, partly on advice seq {... }async {... } client {... }dist {... }server {... } option {... } Client = unit -> 'a Optional = unit -> 'a option Server = unit -> 'a seq = IEnumerable Async ≈ ('a -> unit) -> unit Distribution

F# “Workflow” Syntax async { let! image = readAsync "cat.jpg" let image2 = f image do! writeAsync image2 "dog.jpg" do printfn "done!" return image2 } { for x in > (x,x*x) } [ for x in > (x,x*x) ] [| for x in > (x,x*x) |] seq = IEnumerable seq + meta-program Async member OnClick : EventArgs -> Client member OnPageLoad : unit -> Server { for c in db.Customers do for e in db.Employees do if c.Name = e.Name then yield (c.Name,c.Address,e.Address) member x.OnClick(EventArgs) = client { let! x =... do!... } member x.OnPageLoad() = server {... }

F# “Workflow” Syntax async.Delay(fun () -> async.Bind(readAsync "cat.jpg", (fun image -> async.Bind(async.Return(f image),(fun image2 async.Bind(writeAsync "dog.jpg",(fun () -> async.Bind(async.Return(printfn "done!"),(fun () -> async.Return()))))))))) async { let! image = readAsync "cat.jpg" let image2 = f image do! writeAsync image2 "dog.jpg" do printfn "done!" return image2 } Continuation/ Event callback Asynchronous "non- blocking" action You're actually writing this (approximately):

Full Workflow Syntax & Translation expr =... | expr { cexpr } -- let v = expr in v.Delay(fun () -> «cexpr») | { cexpr } | [| cexpr |] | [ cexpr ] cexpr = let! pat = expr in cexpr -- v.Bind(expr,(fun pat -> «cexpr»)) | let pat = expr in cexpr -- v.Let(expr,(fun pat -> «cexpr»)) | use pat = expr in cexpr -- v.Using(expr,(fun pat -> «cexpr»)) | use! pat = cexpr in cexpr -- v.BindUsing(expr,(fun pat -> «cexpr»)) | do! cexpr1 in cexpr2 -- «let! () = cexpr1 in cexpr2» | do expr in cexpr -- «let () = cexpr1 in cexpr2» | for pat in expr do cexpr -- v.For(expr,(fun pat -> «cexpr»)) | while expr do cexpr -- v.While((fun () -> expr), v.Delay(fun () -> «cexpr»)) | if expr then cexpr else cexpr -- if expr then «cexpr1» else «cexpr2» | if expr then cexpr -- if expr then «cexpr1» else v.Zero() | cexpr; cexpr -- v.Combine(«cexpr1», v.Delay(fun () -> «cexpr2»)) | -> expr -- v.Return(expr) | return expr -- v.Return(expr) | yield expr -- v.Yield(expr) | match expr with [pat -> cexpr] | try cexpr finally cexpr | try cexpr with pat -> cexpr --...

type MBuilder() with member For: #seq * ('a -> M ) -> M member Zero : unit -> M member Sequence : M * M -> M member While : (unit -> bool) * M -> M member Return : 'a -> M member Delay : (unit -> M ) -> M member Using: 'a * ('a -> M ) -> M when 'a :> IDisposable member Let: 'a * ('a -> M ) -> M member Bind: M * ('a -> M ) -> M member TryFinally : M * (unit -> unit) -> M member TryWith : M * (exn -> M ) -> M let async = AsyncBuilder() let seq = SeqBuilder() let attempt = AttemptBuilder()

F# “Workflow” Syntax For "declarative control“, “modalities” and "queries“ Not particularly for tracking effects, though can be used for this Often combined with "separated" imperative programming // dequeueAll : Queue -> seq let dequeueAll(queue:Queue ) = [ while queue.Count <> 0 do yield queue.Dequeue() ] // randomWalk : seq let randomWalk = { let state = ref 0.0 while true do yield state.Value state := state.Value + rand() } // allLines : seq let allLines(file) = { let inputStream = System.IO.File.OpenRead(file) while not inputStream.IsEndOfFile do yield inputStream.ReadLine() }

F# Meta-programming SQL { for c in db.Customers do for e db.Employees do if c.Name = e.Name then yield (c.Name,c.Address,e.Address) SQL : Expr > -> seq Runtime intensional meta programming (= Typed Scheme Quotations) (= Expression Trees) SQLServer

Using F# Workflow Syntax for Async/Reactive Programming

Why is it so hard? To get 50 web pages in parallel? To get from thread to thread? To create a worker thread that reads messages? To handle failure on worker threads?

Why isn’t it this easy? let GetWebPages(urls) = Async.Run (Async.Parallel [ for i in urls -> GetWebPage(i) ])

© 2007 Microsoft Corporation. All rights reserved. Microsoft Confidential. For Internal Use Only. Why isn’t it this easy? let ProcessImages() = Async.Run (Async.Parallel [ for i in 1.. numImages -> ProcessImage(i) ])

Why isn’t it this easy? let task = async {... do! SwitchToNewThread()... do! SwitchToThreadPool()... do! SwitchToGuiThread().... }

Async (“task generators”) Return, Bind, TryCatch, TryFinally, Raise, Delay, Sequence etc. Run, Spawn, SpawnFuture, SpawnChild CancelCheck, WhenCancelled, CancelAsync Parallel (= ForkJoin) SwitchToNewThread, SwitchToThreadPool BuildPrimitive

© 2007 Microsoft Corporation. All rights reserved. Microsoft Confidential. For Internal Use Only. Taming Asynchronous I/O Stream.BeginRead :... Stream.EndRead : IAsyncResult *... Target: make it easy to use Begin/End operations

Stream.ReadAsync = BuildPrimitive(Stream.BeginRead,Stream.EndRead) WebRequest.GetResponseAsync = BuildPrimitive(WebRequest.BeginRead,WebRequest.EndRead) WaitHandle.WaitOneAsync(timeout) = BuildPrimitive(WaitHandle.BeginRead,WaitHandle.EndRead,timeout) Database.GetDataAsync....

Taming Asynchronous I/O using System; using System.IO; using System.Threading; public class BulkImageProcAsync { public const String ImageBaseName = "tmpImage-"; public const int numImages = 200; public const int numPixels = 512 * 512; // ProcessImage has a simple O(N) loop, and you can vary the number // of times you repeat that loop to make the application more CPU- // bound or more IO-bound. public static int processImageRepeats = 20; // Threads must decrement NumImagesToFinish, and protect // their access to it through a mutex. public static int NumImagesToFinish = numImages; public static Object[] NumImagesMutex = new Object[0]; // WaitObject is signalled when all image processing is done. public static Object[] WaitObject = new Object[0]; public class ImageStateObject { public byte[] pixels; public int imageNum; public FileStream fs; } public static void ReadInImageCallback(IAsyncResult asyncResult) { ImageStateObject state = (ImageStateObject)asyncResult.AsyncState; Stream stream = state.fs; int bytesRead = stream.EndRead(asyncResult); if (bytesRead != numPixels) throw new Exception(String.Format ("In ReadInImageCallback, got the wrong number of " + "bytes from the image: {0}.", bytesRead)); ProcessImage(state.pixels, state.imageNum); stream.Close(); // Now write out the image. // Using asynchronous I/O here appears not to be best practice. // It ends up swamping the threadpool, because the threadpool // threads are blocked on I/O requests that were just queued to // the threadpool. FileStream fs = new FileStream(ImageBaseName + state.imageNum + ".done", FileMode.Create, FileAccess.Write, FileShare.None, 4096, false); fs.Write(state.pixels, 0, numPixels); fs.Close(); // This application model uses too much memory. // Releasing memory as soon as possible is a good idea, // especially global state. state.pixels = null; fs = null; // Record that an image is finished now. lock (NumImagesMutex) { NumImagesToFinish--; if (NumImagesToFinish == 0) { Monitor.Enter(WaitObject); Monitor.Pulse(WaitObject); Monitor.Exit(WaitObject); } public static void ProcessImagesInBulk() { Console.WriteLine("Processing images... "); long t0 = Environment.TickCount; NumImagesToFinish = numImages; AsyncCallback readImageCallback = new AsyncCallback(ReadInImageCallback); for (int i = 0; i < numImages; i++) { ImageStateObject state = new ImageStateObject(); state.pixels = new byte[numPixels]; state.imageNum = i; // Very large items are read only once, so you can make the // buffer on the FileStream very small to save memory. FileStream fs = new FileStream(ImageBaseName + i + ".tmp", FileMode.Open, FileAccess.Read, FileShare.Read, 1, true); state.fs = fs; fs.BeginRead(state.pixels, 0, numPixels, readImageCallback, state); } // Determine whether all images are done being processed. // If not, block until all are finished. bool mustBlock = false; lock (NumImagesMutex) { if (NumImagesToFinish > 0) mustBlock = true; } if (mustBlock) { Console.WriteLine("All worker threads are queued. " + " Blocking until they complete. numLeft: {0}", NumImagesToFinish); Monitor.Enter(WaitObject); Monitor.Wait(WaitObject); Monitor.Exit(WaitObject); } long t1 = Environment.TickCount; Console.WriteLine("Total time processing images: {0}ms", (t1 - t0)); } let ProcessImageAsync () = async { let inStream = File.OpenRead(sprintf "Image%d.tmp" i) let! pixels = inStream.ReadAsync(numPixels) let pixels' = TransformImage(pixels,i) let outStream = File.OpenWrite(sprintf "Image%d.done" i) do! outStream.WriteAsync(pixels') do Console.WriteLine "done!" } let ProcessImagesAsyncWorkflow() = Async.Run (Async.Parallel [ for i in 1.. numImages -> ProcessImageAsync i ]) Processing 200 images in parallel

let ProcessImageAsync(i) = async { let inStream = File.OpenRead(sprintf "source%d.jpg" i) let! pixels = inStream.ReadAsync(numPixels) let pixels' = TransformImage(pixels,i) let outStream = File.OpenWrite(sprintf "result%d.jpg" i) do! outStream.WriteAsync(pixels') do Console.WriteLine "done!" } let ProcessImagesAsync() = Async.Run (Async.Parallel [ for i in 1.. numImages -> ProcessImageAsync(i) ]) Taming Asynchronous I/O Read from the file, asynchronously “!” = “asynchronous” Write the result, asynchronously This object coordinates Equivalent F# code (same perf) Generate the tasks and queue them in parallel Open the file, synchronously

Taming Asynchronous I/O using System; using System.IO; using System.Threading; public class BulkImageProcAsync { public const String ImageBaseName = "tmpImage-"; public const int numImages = 200; public const int numPixels = 512 * 512; // ProcessImage has a simple O(N) loop, and you can vary the number // of times you repeat that loop to make the application more CPU- // bound or more IO-bound. public static int processImageRepeats = 20; // Threads must decrement NumImagesToFinish, and protect // their access to it through a mutex. public static int NumImagesToFinish = numImages; public static Object[] NumImagesMutex = new Object[0]; // WaitObject is signalled when all image processing is done. public static Object[] WaitObject = new Object[0]; public class ImageStateObject { public byte[] pixels; public int imageNum; public FileStream fs; } public static void ReadInImageCallback(IAsyncResult asyncResult) { ImageStateObject state = (ImageStateObject)asyncResult.AsyncState; Stream stream = state.fs; int bytesRead = stream.EndRead(asyncResult); if (bytesRead != numPixels) throw new Exception(String.Format ("In ReadInImageCallback, got the wrong number of " + "bytes from the image: {0}.", bytesRead)); ProcessImage(state.pixels, state.imageNum); stream.Close(); // Now write out the image. // Using asynchronous I/O here appears not to be best practice. // It ends up swamping the threadpool, because the threadpool // threads are blocked on I/O requests that were just queued to // the threadpool. FileStream fs = new FileStream(ImageBaseName + state.imageNum + ".done", FileMode.Create, FileAccess.Write, FileShare.None, 4096, false); fs.Write(state.pixels, 0, numPixels); fs.Close(); // This application model uses too much memory. // Releasing memory as soon as possible is a good idea, // especially global state. state.pixels = null; fs = null; // Record that an image is finished now. lock (NumImagesMutex) { NumImagesToFinish--; if (NumImagesToFinish == 0) { Monitor.Enter(WaitObject); Monitor.Pulse(WaitObject); Monitor.Exit(WaitObject); } public static void ProcessImagesInBulk() { Console.WriteLine("Processing images... "); long t0 = Environment.TickCount; NumImagesToFinish = numImages; AsyncCallback readImageCallback = new AsyncCallback(ReadInImageCallback); for (int i = 0; i < numImages; i++) { ImageStateObject state = new ImageStateObject(); state.pixels = new byte[numPixels]; state.imageNum = i; // Very large items are read only once, so you can make the // buffer on the FileStream very small to save memory. FileStream fs = new FileStream(ImageBaseName + i + ".tmp", FileMode.Open, FileAccess.Read, FileShare.Read, 1, true); state.fs = fs; fs.BeginRead(state.pixels, 0, numPixels, readImageCallback, state); } // Determine whether all images are done being processed. // If not, block until all are finished. bool mustBlock = false; lock (NumImagesMutex) { if (NumImagesToFinish > 0) mustBlock = true; } if (mustBlock) { Console.WriteLine("All worker threads are queued. " + " Blocking until they complete. numLeft: {0}", NumImagesToFinish); Monitor.Enter(WaitObject); Monitor.Wait(WaitObject); Monitor.Exit(WaitObject); } long t1 = Environment.TickCount; Console.WriteLine("Total time processing images: {0}ms", (t1 - t0)); } let ProcessImageAsync () = async { let inStream = File.OpenRead(sprintf "Image%d.tmp" i) let! pixels = inStream.ReadAsync(numPixels) let pixels' = TransformImage(pixels,i) let outStream = File.OpenWrite(sprintf "Image%d.done" i) do! outStream.WriteAsync(pixels') do Console.WriteLine "done!" } let ProcessImagesAsyncWorkflow() = Async.Run (Async.Parallel [ for i in 1.. numImages -> ProcessImageAsync i ]) Create 10, 000s of “asynchronous tasks” Mostly queued, suspended and executed in the thread pool Exceptions can be handled properly Cancellation checks inserted automatically Resources can be disposed properly on failure CPU threads are not blocked

let ProcessImage(i) = async { use inStream = File.OpenRead(sprintf "source%d.jpg" i) let! pixels = inStream.ReadAsync(1024*1024) let pixels' = TransformImage(pixels,i) use outStream = File.OpenWrite(sprintf "result%d.jpg" i) do! outStream.WriteAsync(pixels') do Console.WriteLine "done!" } let ProcessImages() = Async.Run (Async.Parallel [ for i in 1.. numImages -> ProcessImage(i) ]) Taming Asynchronous I/O

let ProcessImage(i) = async { use inStream = File.OpenRead(sprintf "source%d.jpg" i) let! pixels = inStream.ReadAsync(1024*1024) let pixels' = TransformImage(pixels,i) use outStream = File.OpenWrite(sprintf "result%d.jpg" i) do! outStream.WriteAsync(pixels') do Console.WriteLine "done!" } let ProcessImages() = Async.Run (Async.Parallel [ for i in 1.. numImages -> ProcessImage(i) ]) Taming Asynchronous I/O

F# - Erlang-style Message Agents open Microsoft.FSharp.Control.Mailboxes let counter = new MailboxProcessor (fun inbox -> let rec loop(n) = async { do printfn "n = %d" n let! msg = inbox.Receive() return! loop(n+msg) } loop(0)) Reactive State Machine

Show me the types type Async = P of { ctxt: AsyncGroup; cont: 'a -> unit; econt: exn -> unit; ccont: OperationCanceledException -> unit; } -> unit Async Exception continuation Success continuation Execution request

Show me the types type Async a = P of { ctxt: AsyncGroup; cont: a -> IO (); econt: exn -> IO (); ccont: OperationCanceledException -> IO (); } -> IO () Async Exception continuation Success continuation Execution request

Microsoft Research F# just released Late Summer: “Community Technology Preview” Thereafter moving to be part of standard Microsoft.NET Tools

THANKS

Books about F# Visit

F# Overview Functional Strong Typing SuccinctType Inference Data Types and Patterns 1 st Class FunctionsMeta-Programming Objects.NET OO Model Interoperable Compact type- inferred classes.NET Visual StudioLibrariesToolsConcurrencyDatabase Tools F# CompilerF# Interactive Visual Studio Integration Math/Plot Bindings Lex and Yacc