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

Slides:



Advertisements
Similar presentations
More about Ruby Maciej Mensfeld Presented by: Maciej Mensfeld More about Ruby dev.mensfeld.pl github.com/mensfeld.
Advertisements

Chapter 2.2 – More about Ruby Maciej Mensfeld Presented by: Maciej Mensfeld More about Ruby dev.mensfeld.pl github.com/mensfeld senior.
3.1 Silberschatz, Galvin and Gagne ©2009 Operating System Concepts – 8 th Edition Process An operating system executes a variety of programs: Batch system.
Executional Architecture
Part IV: Memory Management
COM vs. CORBA.
Concurrency The need for speed. Why concurrency? Moore’s law: 1. The number of components on a chip doubles about every 18 months 2. The speed of computation.
Multithreaded Programs in Java. Tasks and Threads A task is an abstraction of a series of steps – Might be done in a separate thread – Java libraries.
1 Friday, June 16, 2006 "In order to maintain secrecy, this posting will self-destruct in five seconds. Memorize it, then eat your computer." - Anonymous.
Intro to Threading CS221 – 4/20/09. What we’ll cover today Finish the DOTS program Introduction to threads and multi-threading.
Threads Section 2.2. Introduction to threads A thread (of execution) is a light-weight process –Threads reside within processes. –They share one address.
Exceptions in Java Fawzi Emad Chau-Wen Tseng Department of Computer Science University of Maryland, College Park.
CS220 Software Development Lecture: Multi-threading A. O’Riordan, 2009.
Threads 1 CS502 Spring 2006 Threads CS-502 Spring 2006.
An introduction to F# (part 2) Bogdan Brinzarea-Iamandi Banca Romaneasca 25 February 2010.
Lecture 8 Epidemic communication, Server implementation.
1 Advanced Computer Programming Concurrency Multithreaded Programs Copyright © Texas Education Agency, 2013.
Silberschatz, Galvin and Gagne ©2009Operating System Concepts – 8 th Edition Chapter 4: Threads.
REVIEW On Friday we explored Client-Server Applications with Sockets. Servers must create a ServerSocket object on a specific Port #. They then can wait.
1 Instant Data Warehouse Utilities Extended (Again!!) 14/7/ Today I am pleased to announce the publishing of some fantastic new functionality for.
Java Threads. What is a Thread? A thread can be loosely defined as a separate stream of execution that takes place simultaneously with and independently.
1 Web Based Programming Section 8 James King 12 August 2003.
CS 346 – Chapter 4 Threads –How they differ from processes –Definition, purpose Threads of the same process share: code, data, open files –Types –Support.
CS107 References and Arrays By Chris Pable Spring 2009.
The Alternative Larry Moore. 5 Nodes and Variant Input File Sizes Hadoop Alternative.
Synchronized and Monitors. synchronized is a Java keyword to denote a block of code which must be executed atomically (uninterrupted). It can be applied.
CS333 Intro to Operating Systems Jonathan Walpole.
1 CS161 Introduction to Computer Science Topic #9.
Programovací jazyky F# a OCaml Chapter 6. Sequence expressions and computation expressions (aka monads)
Fall 2002CS 150: Intro. to Computing1 Streams and File I/O (That is, Input/Output) OR How you read data from files and write data to files.
Processor Architecture
Multithreaded Programing. Outline Overview of threads Threads Multithreaded Models  Many-to-One  One-to-One  Many-to-Many Thread Libraries  Pthread.
© Janice Regan, CMPT 300, May CMPT 300 Introduction to Operating Systems Operating Systems Processes and Threads.
ICS3U_FileIO.ppt File Input/Output (I/O)‏ ICS3U_FileIO.ppt File I/O Declare a file object File myFile = new File("billy.txt"); a file object whose name.
TAP into async programming
Slide 1/29 Informed Prefetching in ROOT Leandro Franco 23 June 2006 ROOT Team Meeting CERN.
Threads. Readings r Silberschatz et al : Chapter 4.
1 Why Threads are a Bad Idea (for most purposes) based on a presentation by John Ousterhout Sun Microsystems Laboratories Threads!
I/O Software CS 537 – Introduction to Operating Systems.
1 CSC160 Chapter 1: Introduction to JavaScript Chapter 2: Placing JavaScript in an HTML File.
Files and Streams. Objectives Learn about the classes that support file input/output Understand the concept of abstraction and how it related to the file.
SPL/2010 Reactor Design Pattern 1. SPL/2010 Overview ● blocking sockets - impact on server scalability. ● non-blocking IO in Java - java.niopackage ●
Lecturer 3: Processes multithreaded Operating System Concepts Process Concept Process Scheduling Operation on Processes Cooperating Processes Interprocess.
REST API Design. Application API API = Application Programming Interface APIs expose functionality of an application or service that exists independently.
CSE 351 Caches. Before we start… A lot of people confused lea and mov on the midterm Totally understandable, but it’s important to make the distinction.
111 State Management Beginning ASP.NET in C# and VB Chapter 4 Pages
Threads prepared and instructed by Shmuel Wimer Eng. Faculty, Bar-Ilan University 1July 2016Processes.
Chapter 4 – Thread Concepts
Chapter 4: Threads Modified by Dr. Neerja Mhaskar for CS 3SH3.
Introduction to threads
Threads Some of these slides were originally made by Dr. Roger deBry. They include text, figures, and information from this class’s textbook, Operating.
Chapter 4: Threads.
Node.Js Server Side Javascript
Advanced Topics in Concurrency and Reactive Programming: Asynchronous Programming Majeed Kassis.
Thread Fundamentals Header Advanced .NET Threading, Part 1
Chapter 4 – Thread Concepts
CS399 New Beginnings Jonathan Walpole.
Process Management Presented By Aditya Gupta Assistant Professor
Functions CIS 40 – Introduction to Programming in Python
Node.Js Server Side Javascript
12 Asynchronous Programming
Operating Systems Chapter 5: Input/Output Management
Software models - Software Architecture Design Patterns
Lecture Topics: 11/1 General Operating System Concepts Processes
Threads Chapter 4.
Why Threads Are A Bad Idea (for most purposes)
Chapter 4: Threads.
Why Threads Are A Bad Idea (for most purposes)
Why Threads Are A Bad Idea (for most purposes)
Lecture Topics: 11/1 Hand back midterms
Presentation transcript:

Introduction to Concurrency in F# Joey Dodds

F# F# Warmup F# async basics async let! examples Continuations Events

F# Warmup F# Interactive environment Download here

F# Parallel Needs F# has constructs for asynchronous, reactive programming Code should be allowed to execute independent of the main thread Should be able to react quickly to updates in environment...

F# Parallel Needs Why react quickly to updates? Timely response to user input Network requests could complete at any time Disk access is slow GUI updates should be prompt and correct

The old way In many programming languages we can implement reactive solutions with callbacks Callbacks have some problems though: Complex code Difficult to correctly dispose of resource Problems only multiply as code gets bigger

The old way let openFileCallback() = let fs = new Files\.., FileMode.Open, FileAccess.Read, FileShare.Read) let data = Array.create (int fs.Length) 0uy let callback ar = let bytesRead = fs.EndRead(ar) fs.Dispose() printfn "Read Bytes: %i, First bytes were: %i % %i..." bytesRead data.[1] data.[2] data.[3] fs.BeginRead(data, 0, data.Length, (fun ar -> callback ar), null) |> ignore We create a callback function that declares behavior when the read completes

The old way let openFileCallback() = let fs = new Files\.., FileMode.Open, FileAccess.Read, FileShare.Read) let data = Array.create (int fs.Length) 0uy let callback ar = let bytesRead = fs.EndRead(ar) fs.Dispose() printfn "Read Bytes: %i, First bytes were: %i % %i..." bytesRead data.[1] data.[2] data.[3] fs.BeginRead(data, 0, data.Length, (fun ar -> callback ar), null) |> ignore We then pass the callback to BeginRead, which expects it as an argument

The old way let openFileCallback() = let fs = new Files\.., FileMode.Open, FileAccess.Read, FileShare.Read) let data = Array.create (int fs.Length) 0uy let callback ar = let bytesRead = fs.EndRead(ar) fs.Dispose() printfn "Read Bytes: %i, First bytes were: %i % %i..." bytesRead data.[1] data.[2] data.[3] fs.BeginRead(data, 0, data.Length, (fun ar -> callback ar), null) |> ignore We would normally like to use a “use” instead of a “let” here, because it would dispose of the resource as soon as it goes out of scope. Here we can't use “use” because fs will go out of scope at the end of the function. We have to make this call to dispose of the resource. If the program crashes, we might never dispose of it at all.

F# Async Async defines a block of code we would like to run asynchronously We can use let! instead of let let! binds asynchronously The computation in the async block waits until the let! completes While it is waiting it does not block Once the let! Binding completes, the async block continues Might continue on a different thread

F# Async What do we mean when we say let! doesn't block? The computation in the async stops until the binding is complete No program or OS thread is blocked All we need to do is register our async – Fairly low cost per async – Can have thousands of asyncs waiting without much performance cost – Asyncs could even improve performance on a single thread

F# Async In some cases we can also use the “use” keyword in place of let Use bindings are disposed of when they are out of scope We can't use them with callbacks because they may be disposed of too soon In asynchs we can use them, because we don't leave the async until our computation is done

F# Async let openFileAsynchronous = async { use fs = new Files\..., FileMode.Open, FileAccess.Read, FileShare.Read) let data = Array.create (int fs.Length) 0uy let! bytesRead = fs.AsyncRead(data, 0, data.Length) do printfn "Read Bytes: %i, First bytes were: %i %i %i..." bytesRead data.[1] data.[2] data.[3] } We use the async keyword around code we want executed asynchronously. This binding occurs asynchronously. The computation waits here until fs.AsyncRead completes. The right hand side of ! operations must be asynchronous, otherwise they would have no meaning.

Examples Back to the IDE for a couple of examples File reading – Synchronous file read – Asynchronous file read done manually with callbacks – Async file read Prime number finding – C# Style asynchronous prime number finding – Async prime number finding Asynchronous http requests

CPU bound vs IO bound computations The examples fell into two categories CPU Bound – The prime example IO Bound – The file read example – The http example While both use the same programming constructs they have some differences

CPU Bound functions will scale in proportion to the number of threads that can be run simultaneously Running asynchronously will still occupy threads On this machine we saw a 2x speedup at best IO bound functions can scale regardless of threads IO bound computations can often “overlap” This can even work for huge numbers of computations We can see 100x+ speedups even on single cores

Limitations What we have learned so far has some limitations: What do we do if our parallel code throws an exception? What do we do if we need to cancel our parallel jobs? How can we safely update the user with correct information once we have our results?

Continuations All three of those issues can be solved by running our asyncs with Async.RunWithContinuations. Function takes 4 arguments – Async – Continuation – Exception Continuation – Cancellation Continuation

Advantages of Continuations Specify behavior for different error cases Continuations run on the same thread the async was started from If you try to update the GUI from an async, you may not have access With continuations you can “schedule” an update when your computation completes This allows for timely and accurate GUI updates

Advantages of Continuations let async1 (label:System.Windows.Forms.Label) filename = Async.StartWithContinuations( async { label.Text <- "Operation started." use outputFile = System.IO.File.Create(filename) do! outputFile.AsyncWrite(bufferData) }, (fun _ -> label.Text <- "Operation completed."), (fun _ -> label.Text <- "Operation failed."), (fun _ -> label.Text <- "Operation canceled.")) These three functions determine the behavior when the async completes. If we named the argument we could use it as well. For the first we could use the information computed in the async. The second and third could analyze the reason for failure/cancellation.

More limitations Continuations give us more power but: Can't update progress (events) Only know how to perform a fixed number of jobs We can't generate new jobs as work progresses Progress of asyncs generated by Async.Parallel can't be directed (agents)

Events We can use events to allow asyncs to report progress The simplest form of this is reporting when each individual job completes

Worker type AsyncWorker (jobs: seq >) = let jobCompleted = new Event () member x.Start() = let syncContext = SynchronizationContext.CaptureCurrent() let jobs = jobs |> Seq.mapi (fun i job -> (job,i+1)) let work = Async.Parallel [ for (job,jobNumber) in jobs -> async { let! result = job syncContext.RaiseEvent jobCompleted (jobNumber,result) return result } ] Async.Start(work |> Async.Ignore) member x.JobCompleted = jobCompleted.Publish We are going to create a worker that can report when it is done with a task.

Worker type AsyncWorker (jobs: seq >) = let jobCompleted = new Event () member x.Start() = let syncContext = SynchronizationContext.CaptureCurrent() let jobs = jobs |> Seq.mapi (fun i job -> (job,i+1)) let work = Async.Parallel [ for (job,jobNumber) in jobs -> async { let! result = job syncContext.RaiseEvent jobCompleted (jobNumber,result) return result } ] Async.Start(work |> Async.Ignore) member x.JobCompleted = jobCompleted.Publish First we create an event that we can use In the start function, we have to grab the current context so we know where to raise our event.

type AsyncWorker (jobs: seq >) = let jobCompleted = new Event () member x.Start() = let syncContext = SynchronizationContext.CaptureCurrent() let jobs = jobs |> Seq.mapi (fun i job -> (job,i+1)) let work = Async.Parallel [ for (job,jobNumber) in jobs -> async { let! result = job syncContext.RaiseEvent jobCompleted (jobNumber,result) return result } ] Async.Start(work |> Async.Ignore) member x.JobCompleted = jobCompleted.Publish Worker We number off our jobs first and create and compose some asyncs in the way we expect

type AsyncWorker (jobs: seq >) = let jobCompleted = new Event () member x.Start() = let syncContext = SynchronizationContext.CaptureCurrent() let jobs = jobs |> Seq.mapi (fun i job -> (job,i+1)) let work = Async.Parallel [ for (job,jobNumber) in jobs -> async { let! result = job syncContext.RaiseEvent jobCompleted (jobNumber,result) return result } ] Async.Start(work |> Async.Ignore) member x.JobCompleted = jobCompleted.Publish Worker When a job completes, we continue in the async, raising an event in the context we started the async from. The event is aware of the job number and the result

type AsyncWorker (jobs: seq >) = let jobCompleted = new Event () member x.Start() = let syncContext = SynchronizationContext.CaptureCurrent() let jobs = jobs |> Seq.mapi (fun i job -> (job,i+1)) let work = Async.Parallel [ for (job,jobNumber) in jobs -> async { let! result = job syncContext.RaiseEvent jobCompleted (jobNumber,result) return result } ] Async.Start(work |> Async.Ignore) member x.JobCompleted = jobCompleted.Publish Worker As an added bonus of this style, we have encapsulated all of the asynchronous behavior in this function, so the rest of the program doesn't need to be aware of it.

Examples Previous example used on IO and CPU bound computations Worker that can report more about the computation it runs

The End

Following slides are from the draft of this presentation

F# Warmup |> operator is a unique feature that helps write readable F# code To multiply a list of numbers by two and add them together How are we used to doing this from scratch if we already have the function below?

|> Operator How would we write the same function if we had a map function? Or using the F# |> (pipeline) operator

>> Operator Related to the |> operator is the >> (compose) operator We can use this operator when we wish to flow from one function to another without initial arguments For example:

Lets do something in parallel! Our input will be a list of integers Output is a list of integer boolean pairs (number, isprime) We are using a silly slow implementation of IsPrime to help show the speedup run for i in it takes my computer about seconds the executing code is:

Lets do something in parallel! If we know something about ThreadPool APIs we can make a good start:

Lets do something in parallel! Now it runs in about 6 seconds on my dual core machine Great, but the code is far from beautiful

Async Lets look at our original code And try out the F# async keyword…

Async Same performance increase as the ugly version! There is also a library option that gives the same performance:

What did we just do? When we use async { } we are creating objects of the type Async o This is just a type that represents an asynchronous computation with a result of type ‘a Array.map is actually creating an Async for each member of our array Async.Parallel has type seq > -> Async Async.RunSynchronously is typed Async -> 'a

Some notes the async keyword isn’t the only way to create the Async type o Library calls like Stream.AsyncRead o Begin and End method calls The RunSynchronously function isn’t the only way to execute parallel code (more on that later)

A slightly different example The previous example was CPU-bound o Once a task started in a thread, it (probably) occupied that thread throughout the course of its computation We can also do I\O in parallel A great (and very common) example is making requests to web servers The goal is to request data from mulitple webservers o We wish to do this asynchronously o We would also like to be able to react to the responses o And return results to the user in some way

A slightly different example The previous example was CPU-bound o Once a task started in a thread, it (probably) occupied that thread throughout the course of its computation We can also do I\O in parallel A great (and very common) example is making requests to web servers The goal is to request data from mulitple webservers o We wish to do this asynchronously o We would also like to be able to react to the responses o And return results to the user in some way

The code Here is the code to make requests to multiple HTTP servers Notice anything new here?

The code Not only do we have the use keyword, but one of them has ! Use simply discards the value binding as soon as it is out of scope The ! has an interesting meaning in async o It tells the async to wait to proceed until it receives the response o The important thing here is that no thread is blocked o Only active computations occupy threads o Waiting is cheap, so we can wait a lot without slowing things down

F# Scalability Because we never block while we wait and it doesn’t cost much to wait: o Asynchronous I\O can scale extremely well o You can easily have thousands or millions of pending reactions o This can be useful in GUIs or web crawlers

Async.StartWithContinuations If we want more control over what happens when our async completes (or fails) we use Async.StartWithContinuations This function is used in place of Async.RunSynchronously It has usage: Async.StartWithContinuations ( o computation, : the asynchronous computation o continuation, : the function to call on completion o exceptionContinuation, : the function to call on exception o cancellationContinuation) : the function to call on cancellation It has the added advantage that if it starts on the GUI thread, the continuations will be called on the GUI thread. This means it is always safe to update the results if we have them

Using events to report progress StartWithContinuations was nice for reporting more information about our calculations It doesn't allow us to send much information during computation We are going to use an example that reports as soon as an individual computation finishes The first step is to create a type for a worker Our worker has: o an event o a start function o a function to publish events

Using events to report progress Our worker's start function accesses a SynchronizationContext This can basically be seen as a handle that allows asynchronous computations to run code or raise events in the correct place more...

Agents? 3-5 slides

Demo interactive environment? Earlier? With some of the examples?