1 of 65

Efficient Parallel Programming with F# and Hopac

Natallia Dzenisenka

@nata_dzen

2 of 65

Terminology

Synchronous, serial, blocking

All operations are performed one by one.

Asynchronous, non-blocking

Doing something useful while waiting. It is widely used for UI. May not provide performance benefits.

Parallel

Execution of several tasks at the same time unit, provides performance benefits.

Concurrent

Execution of several tasks.

3 of 65

Synchronous, serial, blocking

CODE

WAITING

As if you write your code till it's complete, wait for it to compile and then drink coffee

4 of 65

Asynchronous, non-blocking

CODE

Write your code and then drink coffee at the same time while waiting for compilation

5 of 65

Parallel

CODE

Listening to music while coding: you can do both at the same time unit.

6 of 65

Concurrent

CODE

CODE

CODE

You can’t text your boss at the exact same time as you write code, but you’re basically doing both things

7 of 65

Why F#?

Because F# is a functional programming language where asynchronous programming is very easy;

Monads in F# are implemented as computation expressions;

F# has async {} computation expression.

8 of 65

Async computation expression

let testAsync = async{

...

let! result = someAsyncOperation

...

}

9 of 65

Why Hopac?

Because it provides:

  • Cheap parallelism
  • Avoids memory allocations
  • Locks are held for short periods

10 of 65

When is the best time to use Hopac?

  • Large number of threads

11 of 65

Why “Hopac”?

12 of 65

Authentically known Legend of Hopac

Hopac is also a national Ukrainian dance

13 of 65

14 of 65

15 of 65

What my Ukrainian friends think I’m doing when I say “I’m working on my Hopac”

16 of 65

What I’m actually doing...

17 of 65

Let’s code!

18 of 65

Matrix Multiplication

1

2

3

4

5

6

7

8

9

1

8

7

4

5

6

7

8

9

1

2

3

4

5

6

7

8

9

9

6

5

4

3

2

1

30

24

18

84

69

54

138

114

90

C (3x3)

B (3x3)

A (3x3)

C[1,1] = 1 x 9 + 2 x 6 + 3 x 3 = 30

C[i,j] = C[i,j] + A[i,k] * B[k,j]

19 of 65

Regular Matrix Multiplication

20 of 65

Async Matrix Multiplication

21 of 65

Task Parallel Matrix Multiplication

22 of 65

Hopac Matrix Multiplication

23 of 65

Results: 10x10 matrix

24 of 65

Results: 500x500 matrix

25 of 65

Results: 1000x1000 matrix

26 of 65

Results: 2000x2000 matrix

27 of 65

Results: 2000x2000 matrix�Larger Machine

28 of 65

Results of Matrix Multiplication example

29 of 65

Matrix 2000 x 2000 results on Large Machine

30 of 65

Recursive sum of the tree

1

2

3

4

5

6

7

11

8

9

10

15

12

13

14

Sum = 1 + 2 + 3… + 15 = 120

1

2

3

4

Level

31 of 65

Tree structure

32 of 65

Serial or Synchronous

33 of 65

Async

34 of 65

Tasks

35 of 65

Hopac

36 of 65

Results: Tree of 1,023 elements

37 of 65

Results: Tree of 32,767 elements

38 of 65

Results: Tree of 1,048,575 elements

39 of 65

Results: Tree of 8,388,607 elements

40 of 65

Results of Sum of the Tree example

41 of 65

Results of Sum of the Tree example

42 of 65

Primitives

  • Jobs – lightweight thread of execution
  • Channels — message passing primitives in the form of channels
  • Alternatives — for coordinating and communicating between jobs.

Ch<‘x> - Channel

Alt<‘x> - Alternative

43 of 65

Creation of a Job

44 of 65

Job of performing a Talk

45 of 65

Three talks at the same time

46 of 65

Group picture

47 of 65

Attempt to take group picture at the end of all talks

48 of 65

Attempt to take group picture at the end of all talks

49 of 65

Taking group picture

50 of 65

Good group picture

51 of 65

Waiting for any talk

52 of 65

Waiting for any talk

53 of 65

Recall Sum of a Tree

54 of 65

Different notation

55 of 65

Infixes

<*> performs two jobs in parallel

>>- runs given job and then passes result to a function on the right and runs it.

>>-. some value will be returned

>>= creates a job that first runs the given job and then passes the result of that job to the given function to build another job which will then be run.

>>=. creates a job that runs the given two jobs and returns the result of the second job.

...Many more

56 of 65

Channels

message passing primitives

57 of 65

Alternatives

Ch.take aChannel

Ch.give aChannel aValue

do! Ch.give aChannel aValue

let! aValue = Ch.take aChannel

58 of 65

Alt Timeout

59 of 65

Alt from Promise.read

60 of 65

Alt.choose

61 of 65

Even more infixes

  • X ^=> Y (Alt<'x> -> 'x -> #Job<'y>) -> Alt<'y>)
  • X ^=>. Y (Alt<_> -> Job<'y> -> Alt<'y>)
  • X ^-> Y (Alt<'x> -> ('x -> 'y) -> Alt<'y>)
  • X ^->. Y (Alt<_> -> 'y -> Alt<'y>)
  • X <|> Y
  • X <~> Y

62 of 65

Negative Acknowledgements

63 of 65

Nack example

64 of 65

Nack example running

65 of 65

Thank you!

�Natallia Dzenisenka�@nata_dzen