Haskell

You might also like

Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1of 4

Slide1 Slide2 Slide3- Purely functional- means that everything is done with function calls.

In functional programming, programs are executed by evaluating expressions, in contrast with imperative programming where programs are composed of statements which change global state when executed. Statically,implicitly typed- types are checked by the compiler, but you don't have to declare them (types checked at compile time) Lazy- nothing is done until it needs to be ( means that expressions are not evaluated when they are bound to variables, but their evaluation is deferred until their results are needed by other computations.) Polymorphic- a value can have more than one type. Slide4- Lets review a quick comparison between a standard Java program, and its Haskell equivalent. The first thing that you may notice when looking at a Haskell program is that there are no brackets. In Haskell , you only apply brackets when attempting to group things together. The first line at the top of the program that starts with welcomeMessage is actually a function; it accepts a string and returns the welcome message. This dollar sign simply tells Haskell to first perform whats on the right side of the dollar sign, and then move on to the left. In Haskell, you could pass a function as a parameter to another function; so Haskell doesnt know if you are trying to pass the welcomeMessage function to putStrLn, or process it first. Slide5 Slide6- Parallelism- Ideally, this should be done invisibly, and with no semantic changes. Concurrency- While a concurrent Haskell program can run on a parallel machine, the primary goal of using concurrency is not to gain performance, but rather because that is the simplest and most direct way to write the program.( Improve performance by hiding latency for IO-heavy programs) Slide7 Slide8- Why so many approaches?Different forms of parallelism have different demands: a) data parallelism is about doing the same operations for many pieces of data; a particular common form that warrants dedicated support (dph, repa) b) task or control parallelism is about dividing the overall work into many parts these approaches can be used for data parallelism, too (parallel, monad-par) Slide10 Slide11- a strategy that introduces parallelism ;R from reduce; How much of a value ie evaluated; Compare with the time of sequential program-> we see a speedup of 1.7

Slide12 Slide13- a par b- a spark is created for a; Runtime sees chance to convert spark into a thread; Which in turn may get run in parallel, on another core ; 'b' is returned; Slide14- The user does not need to explicitly create any threads or write any code for inter-thread communication or synchronization. Slide 15- The runtime decies when to push down a spark depending on: workload or cost of the value( This allows `par` to be very cheap; Can use it almost anywhere, to over approximate the parallelism in our code ) Pesq combinator: pseq :: a b b
Says not to create a spark, instead: evaluate 'a' in the current thread, then return b ;

Ensures work is run in the right thread Slide16 Slide17Slide18- forkIO :: IO () IO ThreadId - Takes a block of code to run, and executes it in a new Haskell thread Slide19 Slide20- We need to communicate with threads somehow. One simple way is via asynchronous messages. throwTo and catch/handle Good technique to know Good for writing fault tolerant code Shared memory In pure code, values are immutable, so safe to share However, with threads, we use shared, mutable synchronizing variables to communicate Slide 21dupa instructiuni:

put on a full MVar causes the thread to sleep until the MVar is empty ; take on an empty MVar blocks until it is full; The runtime will wake you up when you're needed Slide 22 Slide 23Slide 24- ce e un optimistic model ? Transactions run inside atomic blocks assuming no conflicts System checks consistency at the end of the transaction Retry if conflicts Requires control of side effects (handled in the type system)

Codul explicat Transaction code can only run inside atomic blocks Inside atomic blocks it appears as if no other threads are running (notion of isolation) However, the system uses logs and rollback to handle conflicts 'orElse' lets us compose atomic blocks into larger pieces

retry: How does the runtime know when to wake up an atomic section? It blocks the thread until something changes in one of the in-scope transaction variables. Automatically waits until we can make progress! orElse: trying alternatives Don't always just want to retry forever orElse :: STM a STM a STM a ; Compose two atomic sections into one . If the first needs to retry, run the second. Slide 25 Slide 26 Flat data parallelism - Apply the same sequential function f, in parallel, to every element of a large collection of values a. Not only is f sequential, but it has a similar run-time for each element of the collection. sumSq :: [: Float :] -> Float sumSq a = sumP [: x*x | x <- a :] The data type [: Float :] is pronounced parallel vector of Float. We use a bracket notation reminiscent of lists, because parallel vectors are similar to lists in that consist of an sequence of elements. Notice that there is no forkIO, and no par. The parallelism comes implicitly from use of the primitives operating on parallel vectors, sump .Flat data parallelism is not restricted to consuming a single array. For example, here is how we might take the product of two vectors, by multiplying corresponding elements and adding up the results Nested data parallelism- Apply the same function f, in parallel, to every element of a large collection of values a. However, f may itself be a (nested) data-parallel function, and does not need to have a similar run-time for each element of a. For example, here is how we might multiply a matrix by a vector: That is, for each row of the matrix, multiply it by the vector v using vecMul. Here we are calling a data-parallel function vecMul from inside a data-parallel operation Slide 28 Slide 29 Slide 30

In Haskell, the strategy is to give the user control over which expressions are sensible to run in parallel What is a strategy? A strategy is a description of how and when a value of a particular type should be evaluated.Strategies can in particular specify: that evaluation should be more eager than by default, that parts of the value should potentially be evaluated in parallel. Strategies can then be applied to terms of that type and turn them into annotated terms. Annotated terms can be run, which means that the strategy will be used in the actual evaluation of the term. Sparks are not thread but more of unit of computation (tasks to put it in C#/Java terms). So it's the Haskell way of implementing the task parallelism. forkIO introduces Haskell threads (which map down onto fewer real OS threads). Sparks create entries in the work queues for each thread, from which they'll take tasks to execute if the thread becomes idle. As a result sparks are very cheap (you might have billions of them in a program, while you probably won't have more than a million Haskell threads, and less than a dozen OS threads on half a dozen cores). A standard way to keep consistency in Haskell is MVar. But MVar is slow, since each MVar is protected with a home-brewed spin lock. Sparks

A spark is created whenever a computation is marked for parallel execution using rpar . For every capability (or HEC, think core), the RTS maintains a spark queue. If a capability is idle, it looks at all the spark queues for work to steal. It then converts the spark and executes the computation.

Creation and conversion


When sparks are created, creation can fail because the queue is full (overow), the

expression is already evaluated (dud).


When sparks are in the queue, they can be run (converted), become evaluated

independently (zzle), be garbage collected if nothing else needs them.

You might also like