KEMBAR78
Async and Parallel F# | PPTX
Async and Parallel Programming in F#Matthew PodwysockiSenior Consultanthttp://codebetter.com/@mattpodwysocki
AgendaF# in 15 MinutesWhy is concurrent programming so hard?What can F# do to help?
...a functional, object-oriented, imperative and explorative programming language for .NET with influences from OCaml, C#, Haskell and ErlangHi! I’m F#
F# in 15 Minutes – The FactsF# is a general purpose .NETlanguageF# is a multi-paradigm languageF# is a statically-typed language
F# in 15 Minutes - The Syntaxbinding names to valuesletlets = "Hello World"let (x, y) = (45, 54)let answer = x + ylet numbers = [1 .. 10]let odds = [1; 3; 5; 7; 9]let square x = x * xlet squareOf4 = square 4
F# in 15 Minutes - The Syntaxfunctions as valuesfunlet square x = x * xlet squares = List.map (fun x -> x * x) [1..10]let squares = List.map square [1..10]Operators are functions too!
F# in 15 Minutes – The Syntax|>bringing order to chaoslet (|>) x f = f xletsumOfSquares =   List.sum (List.map square [1..10])letsumOfSquares = [1..10]                    |> List.map square                   |> List.sum<|>><<See also:
F# in 15 Minutes – The Syntaxdiscriminated unionstypetype Suit = | Spade | Heart | Club | Diamondtype Rank = | Ace | King | Queen | Jack            | Value ofinttype Card = Card of Suit * RankMicrosoft Confidential
F# in 15 Minutes – The Syntaxpattern matchingmatchletcardValue (Card(s,r)) =match r with  | Ace                 -> 11  | King | Queen | Jack -> 10  | Value(x)            -> xlet (x, y) = ("x", "y")let [a; b] = [1 ; 2]Microsoft Confidential
Concurrent programmingwith shared state…Is really hard!Microsoft Confidential
Shared State Gives Us…Race conditions!Obscure error messages!Late night debugging!Locks, mutexes and semaphores, oh my!Microsoft Confidential
How Can F# Help Us?GranularityPurityImmutabilityLibraries
In Praise of ImmutabilityImmutable objects... can be relied upon... can transfer between threads... can be aliased safely... lead to (different) optimization opportunities
There is no silver bullet
Concurrency StylesAsynchronous ProgrammingParallel ProgrammingDataTaskActor Model Concurrency
Asynchronous Programming
publicstaticvoidProcessImagesInBulk(){Console.WriteLine("Processing images...  ");long t0 = Environment.TickCount;NumImagesToFinish = numImages;AsyncCallbackreadImageCallback = newAsyncCallback(ReadInImageCallback);for (inti = 0; i < numImages; i++)  {ImageStateObject state = newImageStateObject();state.pixels = newbyte[numPixels];state.imageNum = i;FileStreamfs = newFileStream(ImageBaseName + i + ".tmp",FileMode.Open, FileAccess.Read, FileShare.Read, 1, true);state.fs = fs;fs.BeginRead(state.pixels, 0, numPixels, readImageCallback,        state);  }boolmustBlock = 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));}publicstaticvoidReadInImageCallback(IAsyncResultasyncResult){ImageStateObject state = (ImageStateObject)asyncResult.AsyncState;Streamstream = state.fs;intbytesRead = stream.EndRead(asyncResult);if (bytesRead != numPixels)thrownewException(String.Format        ("In ReadInImageCallback, got the wrong number of " +"bytes from the image: {0}.", bytesRead));ProcessImage(state.pixels, state.imageNum);stream.Close();FileStreamfs = newFileStream(ImageBaseName + state.imageNum +".done", FileMode.Create, FileAccess.Write, FileShare.None,      4096, false);fs.Write(state.pixels, 0, numPixels);fs.Close();state.pixels = null;fs = null;lock (NumImagesMutex)  {NumImagesToFinish--;if (NumImagesToFinish == 0)    {Monitor.Enter(WaitObject);Monitor.Pulse(WaitObject);Monitor.Exit(WaitObject);    }  }}using System;using System.IO;usingSystem.Threading;usingSystem.Runtime.InteropServices;usingSystem.Runtime.Remoting.Messaging;usingSystem.Security.Permissions;publicclassBulkImageProcAsync{publicconstStringImageBaseName = "tmpImage-";publicconstintnumImages = 200;publicconstintnumPixels = 512 * 512;publicstaticintprocessImageRepeats = 20;publicstaticintNumImagesToFinish = numImages;publicstaticObject[] NumImagesMutex = newObject[0];publicstaticObject[] WaitObject = newObject[0];publicclassImageStateObject  {publicbyte[] pixels;publicintimageNum;publicFileStreamfs;  }“Asynchronous File I/O”http://msdn.microsoft.com/en-us/library/kztecsys.aspxState of Asynchronous I/O
letProcessImageAsynci =async { useinStream = File.OpenRead(sprintf"Image%d.tmp"i)let! pixels = inStream.AsyncRead(numPixels)let pixels' = ProcessImage(pixels, i)useoutStream = File.OpenWrite(sprintf"Image%d.done"i)do!outStream.AsyncWrite(pixels') }letProcessImagesAsync() =let tasks = [ foriin 1..numImages ->ProcessImageAsync(i) ]letparallelTasks = Async.Parallel tasksAsync.RunSynchronouslyparallelTasksWhy Isn’t it This Easy?
Read streamasynchronouslyletProcessImageAsynci =async { useinStream = File.OpenRead(sprintf"Image%d.tmp"i)let! pixels = inStream.AsyncRead(numPixels)let pixels' = ProcessImage(pixels, i)useoutStream = File.OpenWrite(sprintf"Image%d.done"i)do!outStream.AsyncWrite(pixels') }letProcessImagesAsync() =let tasks = [ for i in 1..numImages ->ProcessImageAsynci ]letparallelTasks = Async.Parallel tasksAsync.RunSynnchronouslyparallelTasksThis object coordinatesWrite stream asynchronouslyGenerate the tasks and queue them in parallel“!” = “asynchronous”Digging Deeper…
letgetHtml (url:string) =async { let request = WebRequest.Createurluse! response = request.AsyncGetResponse()use stream = response.GetResponseStream()use reader = newStreamReader(stream)return! reader.AsyncReadToEnd() }What we’re really writingletgetHtml (url:string) =async.Delay(fun () ->let request = WebRequest.Createurlasync.Bind(request.AsyncGetResponse(), funresponse ->async.Using(response, fun response ->async.Using(response.GetResponseStream(), fun stream ->async.Using(new StreamReader(stream), fun reader ->reader.AsyncReadToEnd())))))
How does it work?Success ContinuationAsync<T>Execution RequestException ContinuationCancellation Continuation
Anatomy of an Async OperationAsync operationsBegin/EndtypeSystem.Net.WebRequestwithmemberthis.AsyncGetRequestStream() =Async.BuildPrimitive(this.BeginGetRequestStream, this.EndGetRequestStream)
What Do We Get For Free?Code that makes senseException propagationCancellation checkingSimple resource lifetime management
Twitter Example
Parallel ProgrammingTask ParallelData Parallel
Data Parallel ProgrammingPLINQEnable F# developers to leverage parallel hardwareAbstracts away parallelism detailsPartitions and merges data intelligentlyWorks on any seq<'a>/IEnumerable<T>let q = ratings  |> PSeq.adapt  |> PSeq.filter(funp ->p.Name = movieName &&p.Rating >= 3.0 &&p.Rating <= 5.0)  |> PSeq.sortBy(fun p ->p.Rating)  |> PSeq.map(funp ->p.CustomerId)
Task Parallel ProgrammingEnable F# developers to create tasks in parallelletcomputeHash path algorithm =async { use stream = File.OpenRead pathlet! bytes = stream.AsyncRead(intstream.Length)let crypt = HashAlgorithm.Create algorithmreturncrypt.ComputeHash bytes }let algorithms = ["MD5";"SHA1";"SHA256";"SHA384";"SHA512"]let [|md5;sha1;sha256;sha384;sha512|] =Async.RunSynchronously(Async.Parallel     [for algorithm in algorithms ->computeHash path algorithm])
Task Parallel + Async WorkflowsTPL Tasks integrated in .NET 4.0 Async WorkflowsIntegrate with pre-defined tasksCalculate FuturesletgetStreamData (uri:string) =async { let request = WebRequest.Createuriuse! response = request.AsyncGetResponse()return [use stream = response.GetResponseStream()use reader = new StreamReader(stream)while not reader.EndOfStreamdoyieldreader.ReadLine()] }let result = Async.CreateAsTask <| getStreamDatamyUrido result.Start()letresultValue = result.Value
Bing Translator Example
Actor Model ConcurrencyLots of little tasksEach process does one taskAnt ColonyAnts are processes sending messages to each other
Actor Model in Action…let (<--) (m:'aMailboxProcessor) msg = m.Post(msg)typePinger = PongtypePonger = Ping ofMailboxProcessor<Pinger> | Stopletponger = newMailboxProcessor<Ponger>(funinbox ->let rec loop pongCount =async { let! msg = inbox.Receive()matchmsgwith              | Ping outbox ->                  outbox <-- Pongreturn! loop(pongCount + 1)              | Stop -> return () }    loop 0)
Actor Model in Action…letpinger count pong =  newMailboxProcessor<Pinger>(funinbox ->    let rec sendPing() =       async { pong <-- Ping(inbox)              return! loop (count - 1) }    and loop pingsLeft =      async { let! msg = inbox.Receive()              matchmsgwith              | Pong ->                  ifpingsLeft > 0 then                    pong <-- Ping(inbox)                    return! loop(pingsLeft - 1)                  else                                       pong <-- Stop                    return () }    sendPing())
Web Crawling Example
Ant Colony Example
High Performance ComputingMPI.NETDryad/DryadLINQ
What’s in Store for 2010?
Ways to Learn F#http://www.fsharp.netF# Interactive (FSI)Language SpecificationF# Team BlogsF# (FSharp) Discussion DLhttp://cs.hubfs.netCodePlex F# Samples.NET ReflectorGo to Definition
Books about F#
Resources - BlogsDon Symehttp://blogs.msdn.com/dsyme/Luke Hobanhttp://blogs.msdn.com/lukeh/Brian McNamarahttp://lorgonblog.spaces.live.com/Chris Smithhttp://blogs.msdn.com/chrsmith/Jomo Fisherhttp://blogs.msdn.com/jomo_fisher/Planet F#http://feeds.feedburner.com/planet_fsharp

Async and Parallel F#

  • 1.
    Async and ParallelProgramming in F#Matthew PodwysockiSenior Consultanthttp://codebetter.com/@mattpodwysocki
  • 2.
    AgendaF# in 15MinutesWhy is concurrent programming so hard?What can F# do to help?
  • 3.
    ...a functional, object-oriented,imperative and explorative programming language for .NET with influences from OCaml, C#, Haskell and ErlangHi! I’m F#
  • 5.
    F# in 15Minutes – The FactsF# is a general purpose .NETlanguageF# is a multi-paradigm languageF# is a statically-typed language
  • 6.
    F# in 15Minutes - The Syntaxbinding names to valuesletlets = "Hello World"let (x, y) = (45, 54)let answer = x + ylet numbers = [1 .. 10]let odds = [1; 3; 5; 7; 9]let square x = x * xlet squareOf4 = square 4
  • 7.
    F# in 15Minutes - The Syntaxfunctions as valuesfunlet square x = x * xlet squares = List.map (fun x -> x * x) [1..10]let squares = List.map square [1..10]Operators are functions too!
  • 8.
    F# in 15Minutes – The Syntax|>bringing order to chaoslet (|>) x f = f xletsumOfSquares = List.sum (List.map square [1..10])letsumOfSquares = [1..10] |> List.map square |> List.sum<|>><<See also:
  • 9.
    F# in 15Minutes – The Syntaxdiscriminated unionstypetype Suit = | Spade | Heart | Club | Diamondtype Rank = | Ace | King | Queen | Jack | Value ofinttype Card = Card of Suit * RankMicrosoft Confidential
  • 10.
    F# in 15Minutes – The Syntaxpattern matchingmatchletcardValue (Card(s,r)) =match r with | Ace -> 11 | King | Queen | Jack -> 10 | Value(x) -> xlet (x, y) = ("x", "y")let [a; b] = [1 ; 2]Microsoft Confidential
  • 11.
    Concurrent programmingwith sharedstate…Is really hard!Microsoft Confidential
  • 12.
    Shared State GivesUs…Race conditions!Obscure error messages!Late night debugging!Locks, mutexes and semaphores, oh my!Microsoft Confidential
  • 13.
    How Can F#Help Us?GranularityPurityImmutabilityLibraries
  • 14.
    In Praise ofImmutabilityImmutable objects... can be relied upon... can transfer between threads... can be aliased safely... lead to (different) optimization opportunities
  • 15.
    There is nosilver bullet
  • 16.
    Concurrency StylesAsynchronous ProgrammingParallelProgrammingDataTaskActor Model Concurrency
  • 17.
  • 18.
    publicstaticvoidProcessImagesInBulk(){Console.WriteLine("Processing images... ");long t0 = Environment.TickCount;NumImagesToFinish = numImages;AsyncCallbackreadImageCallback = newAsyncCallback(ReadInImageCallback);for (inti = 0; i < numImages; i++) {ImageStateObject state = newImageStateObject();state.pixels = newbyte[numPixels];state.imageNum = i;FileStreamfs = newFileStream(ImageBaseName + i + ".tmp",FileMode.Open, FileAccess.Read, FileShare.Read, 1, true);state.fs = fs;fs.BeginRead(state.pixels, 0, numPixels, readImageCallback, state); }boolmustBlock = 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));}publicstaticvoidReadInImageCallback(IAsyncResultasyncResult){ImageStateObject state = (ImageStateObject)asyncResult.AsyncState;Streamstream = state.fs;intbytesRead = stream.EndRead(asyncResult);if (bytesRead != numPixels)thrownewException(String.Format ("In ReadInImageCallback, got the wrong number of " +"bytes from the image: {0}.", bytesRead));ProcessImage(state.pixels, state.imageNum);stream.Close();FileStreamfs = newFileStream(ImageBaseName + state.imageNum +".done", FileMode.Create, FileAccess.Write, FileShare.None, 4096, false);fs.Write(state.pixels, 0, numPixels);fs.Close();state.pixels = null;fs = null;lock (NumImagesMutex) {NumImagesToFinish--;if (NumImagesToFinish == 0) {Monitor.Enter(WaitObject);Monitor.Pulse(WaitObject);Monitor.Exit(WaitObject); } }}using System;using System.IO;usingSystem.Threading;usingSystem.Runtime.InteropServices;usingSystem.Runtime.Remoting.Messaging;usingSystem.Security.Permissions;publicclassBulkImageProcAsync{publicconstStringImageBaseName = "tmpImage-";publicconstintnumImages = 200;publicconstintnumPixels = 512 * 512;publicstaticintprocessImageRepeats = 20;publicstaticintNumImagesToFinish = numImages;publicstaticObject[] NumImagesMutex = newObject[0];publicstaticObject[] WaitObject = newObject[0];publicclassImageStateObject {publicbyte[] pixels;publicintimageNum;publicFileStreamfs; }“Asynchronous File I/O”http://msdn.microsoft.com/en-us/library/kztecsys.aspxState of Asynchronous I/O
  • 19.
    letProcessImageAsynci =async {useinStream = File.OpenRead(sprintf"Image%d.tmp"i)let! pixels = inStream.AsyncRead(numPixels)let pixels' = ProcessImage(pixels, i)useoutStream = File.OpenWrite(sprintf"Image%d.done"i)do!outStream.AsyncWrite(pixels') }letProcessImagesAsync() =let tasks = [ foriin 1..numImages ->ProcessImageAsync(i) ]letparallelTasks = Async.Parallel tasksAsync.RunSynchronouslyparallelTasksWhy Isn’t it This Easy?
  • 20.
    Read streamasynchronouslyletProcessImageAsynci =async{ useinStream = File.OpenRead(sprintf"Image%d.tmp"i)let! pixels = inStream.AsyncRead(numPixels)let pixels' = ProcessImage(pixels, i)useoutStream = File.OpenWrite(sprintf"Image%d.done"i)do!outStream.AsyncWrite(pixels') }letProcessImagesAsync() =let tasks = [ for i in 1..numImages ->ProcessImageAsynci ]letparallelTasks = Async.Parallel tasksAsync.RunSynnchronouslyparallelTasksThis object coordinatesWrite stream asynchronouslyGenerate the tasks and queue them in parallel“!” = “asynchronous”Digging Deeper…
  • 21.
    letgetHtml (url:string) =async{ let request = WebRequest.Createurluse! response = request.AsyncGetResponse()use stream = response.GetResponseStream()use reader = newStreamReader(stream)return! reader.AsyncReadToEnd() }What we’re really writingletgetHtml (url:string) =async.Delay(fun () ->let request = WebRequest.Createurlasync.Bind(request.AsyncGetResponse(), funresponse ->async.Using(response, fun response ->async.Using(response.GetResponseStream(), fun stream ->async.Using(new StreamReader(stream), fun reader ->reader.AsyncReadToEnd())))))
  • 22.
    How does itwork?Success ContinuationAsync<T>Execution RequestException ContinuationCancellation Continuation
  • 23.
    Anatomy of anAsync OperationAsync operationsBegin/EndtypeSystem.Net.WebRequestwithmemberthis.AsyncGetRequestStream() =Async.BuildPrimitive(this.BeginGetRequestStream, this.EndGetRequestStream)
  • 24.
    What Do WeGet For Free?Code that makes senseException propagationCancellation checkingSimple resource lifetime management
  • 25.
  • 26.
  • 27.
    Data Parallel ProgrammingPLINQEnableF# developers to leverage parallel hardwareAbstracts away parallelism detailsPartitions and merges data intelligentlyWorks on any seq<'a>/IEnumerable<T>let q = ratings |> PSeq.adapt |> PSeq.filter(funp ->p.Name = movieName &&p.Rating >= 3.0 &&p.Rating <= 5.0) |> PSeq.sortBy(fun p ->p.Rating) |> PSeq.map(funp ->p.CustomerId)
  • 28.
    Task Parallel ProgrammingEnableF# developers to create tasks in parallelletcomputeHash path algorithm =async { use stream = File.OpenRead pathlet! bytes = stream.AsyncRead(intstream.Length)let crypt = HashAlgorithm.Create algorithmreturncrypt.ComputeHash bytes }let algorithms = ["MD5";"SHA1";"SHA256";"SHA384";"SHA512"]let [|md5;sha1;sha256;sha384;sha512|] =Async.RunSynchronously(Async.Parallel [for algorithm in algorithms ->computeHash path algorithm])
  • 29.
    Task Parallel +Async WorkflowsTPL Tasks integrated in .NET 4.0 Async WorkflowsIntegrate with pre-defined tasksCalculate FuturesletgetStreamData (uri:string) =async { let request = WebRequest.Createuriuse! response = request.AsyncGetResponse()return [use stream = response.GetResponseStream()use reader = new StreamReader(stream)while not reader.EndOfStreamdoyieldreader.ReadLine()] }let result = Async.CreateAsTask <| getStreamDatamyUrido result.Start()letresultValue = result.Value
  • 30.
  • 31.
    Actor Model ConcurrencyLotsof little tasksEach process does one taskAnt ColonyAnts are processes sending messages to each other
  • 32.
    Actor Model inAction…let (<--) (m:'aMailboxProcessor) msg = m.Post(msg)typePinger = PongtypePonger = Ping ofMailboxProcessor<Pinger> | Stopletponger = newMailboxProcessor<Ponger>(funinbox ->let rec loop pongCount =async { let! msg = inbox.Receive()matchmsgwith | Ping outbox -> outbox <-- Pongreturn! loop(pongCount + 1) | Stop -> return () } loop 0)
  • 33.
    Actor Model inAction…letpinger count pong =  newMailboxProcessor<Pinger>(funinbox ->    let rec sendPing() =       async { pong <-- Ping(inbox)              return! loop (count - 1) }    and loop pingsLeft =      async { let! msg = inbox.Receive()              matchmsgwith              | Pong ->                  ifpingsLeft > 0 then                    pong <-- Ping(inbox)                    return! loop(pingsLeft - 1)                  else                     pong <-- Stop                    return () }    sendPing())
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
    Ways to LearnF#http://www.fsharp.netF# Interactive (FSI)Language SpecificationF# Team BlogsF# (FSharp) Discussion DLhttp://cs.hubfs.netCodePlex F# Samples.NET ReflectorGo to Definition
  • 39.
  • 40.
    Resources - BlogsDonSymehttp://blogs.msdn.com/dsyme/Luke Hobanhttp://blogs.msdn.com/lukeh/Brian McNamarahttp://lorgonblog.spaces.live.com/Chris Smithhttp://blogs.msdn.com/chrsmith/Jomo Fisherhttp://blogs.msdn.com/jomo_fisher/Planet F#http://feeds.feedburner.com/planet_fsharp

Editor's Notes

  • #12 What is the Problem?Multithreaded programming is hard todayDoable by only a subgroup of senior specialistsParallel patterns are not prevalent, well known, nor easy to implementSo many potential problemsRaces, deadlocks, livelocks, lock convoys, cache coherency overheads, lost event notifications, broken serializability, priority inversion, and so on…Businesses have little desire to go deepBest developers should focus on business value, not concurrencyNeed simple ways to allow all developers to write concurrent code