Slide 1

Slide 1 text

Safe and Scalable Concurrent Programming in Scala 1 Philipp Haller 10th Multicore Day 2016 Stockholm, Sweden December 1st, 2016 KTH Royal Institute of Technology Sweden

Slide 2

Slide 2 text

Programming a Concurrent World 2

Slide 3

Slide 3 text

Programming a Concurrent World • How to compose programs handling 2

Slide 4

Slide 4 text

Programming a Concurrent World • How to compose programs handling • asynchronous events? 2

Slide 5

Slide 5 text

Programming a Concurrent World • How to compose programs handling • asynchronous events? • streams of asynchronous events? 2

Slide 6

Slide 6 text

Programming a Concurrent World • How to compose programs handling • asynchronous events? • streams of asynchronous events? • distributed events? 2

Slide 7

Slide 7 text

Programming a Concurrent World • How to compose programs handling • asynchronous events? • streams of asynchronous events? • distributed events? ➟ Programming abstractions for concurrency! 2

Slide 8

Slide 8 text

What is Scala? • Integrates object-oriented and functional programming • Statically typed • Lightweight syntax (via type inference) • Compilation targets: JVM, JavaScript • Fully interoperable with Java and JavaScript (no glue code) • As fast as Java • Open source development backed by:
 EPFL, Lightbend Inc., and Scala Center (non-profit) 3

Slide 9

Slide 9 text

What is Scala? • Integrates object-oriented and functional programming • Statically typed • Lightweight syntax (via type inference) • Compilation targets: JVM, JavaScript • Fully interoperable with Java and JavaScript (no glue code) • As fast as Java • Open source development backed by:
 EPFL, Lightbend Inc., and Scala Center (non-profit) 3 Advisory board members include Goldman Sachs, IBM, SAP, and Verizon

Slide 10

Slide 10 text

Rankings: RedMonk Q316 4 Source: http://redmonk.com/sogrady/2016/07/20/language-rankings-6-16/

Slide 11

Slide 11 text

Rankings: RedMonk Q316 4 Source: http://redmonk.com/sogrady/2016/07/20/language-rankings-6-16/ # of tags on StackOverflow

Slide 12

Slide 12 text

Rankings: RedMonk Q316 4 Source: http://redmonk.com/sogrady/2016/07/20/language-rankings-6-16/ # of tags on StackOverflow # of projects on GitHub

Slide 13

Slide 13 text

Rankings: RedMonk Q316 4 Source: http://redmonk.com/sogrady/2016/07/20/language-rankings-6-16/ # of tags on StackOverflow # of projects on GitHub

Slide 14

Slide 14 text

Rankings: RedMonk Q316 (zoomed) 5 Source: http://redmonk.com/sogrady/2016/07/20/language-rankings-6-16/

Slide 15

Slide 15 text

Concurrent Programming in Scala 6

Slide 16

Slide 16 text

Example Image data 7

Slide 17

Slide 17 text

Example Image data apply filter 7

Slide 18

Slide 18 text

Example Image data apply filter 7

Slide 19

Slide 19 text

Example Image data apply filter Image processing pipeline: filter 1 filter 2 7

Slide 20

Slide 20 text

Futures 8 val imgData: Buffer = .. val filter: Filter = .. val futImgData = Future { filter.applyTo(imgData) } futImgData.foreach { imgDataOut => // .. }

Slide 21

Slide 21 text

Futures: Two Filters 9 val futImgDataOut1 = Future { filter1.applyTo(imgData) } val futImgDataOut2 = futImgDataOut1.map { imgDataOut1 => filter2.applyTo(imgDataOut1) } futImgDataOut2.foreach { imgDataOut2 => // .. }

Slide 22

Slide 22 text

Futures: Composition 10 def applyFilter(imgData: Buffer, filter: Filter): Future[Buffer] = .. val futImgDataOut1 = applyFilter(imgData, filter1) val futImgDataOut2 = futImgDataOut1.flatMap { imgDataOut1 => applyFilter(imgDataOut1, filter2) } futImgDataOut2.foreach { imgDataOut2 => // .. }

Slide 23

Slide 23 text

Futures: Composition 10 def applyFilter(imgData: Buffer, filter: Filter): Future[Buffer] = .. val futImgDataOut1 = applyFilter(imgData, filter1) val futImgDataOut2 = futImgDataOut1.flatMap { imgDataOut1 => applyFilter(imgDataOut1, filter2) } futImgDataOut2.foreach { imgDataOut2 => // .. } How to process many images efficiently?

Slide 24

Slide 24 text

Actors 11 class Stage(filter: Filter, next: ActorRef) extends Actor { def receive = { case Process(imgData) => val imgDataOut = filter.applyTo(imgData) next ! Process(imgDataOut) case Stop() => context.stop(self) } }

Slide 25

Slide 25 text

Is this all built into Scala? 12

Slide 26

Slide 26 text

Futures 13 val imgData: Buffer = .. val filter: Filter = .. val futImgData = Future { filter.applyTo(imgData) } futImgData.foreach { imgDataOut => // .. }

Slide 27

Slide 27 text

Futures 14 val imgData: Buffer = .. val filter: Filter = .. val futImgData: Future[Buffer] = Future.apply[Buffer]({ filter.applyTo(imgData) }) futImgData.foreach { imgDataOut => // .. }

Slide 28

Slide 28 text

Futures Creating a future: 15 object Future { def apply[T](body: => T): Future[T] }

Slide 29

Slide 29 text

Futures Creating a future: 15 object Future { def apply[T](body: => T): Future[T] } Singleton object

Slide 30

Slide 30 text

Futures Creating a future: 15 object Future { def apply[T](body: => T): Future[T] } Singleton object Generic type parameter

Slide 31

Slide 31 text

Futures Creating a future: 15 object Future { def apply[T](body: => T): Future[T] } Singleton object Generic type parameter “Code block” with result type T

Slide 32

Slide 32 text

Actors: Akka Library 16 class Stage(filter: Filter, next: ActorRef) extends Actor { def receive = { case Process(imgData) => val imgDataOut = filter.applyTo(imgData) next ! Process(imgDataOut) case Stop() => context.stop(self) } }

Slide 33

Slide 33 text

Actors: Akka Library 16 class Stage(filter: Filter, next: ActorRef) extends Actor { def receive = { case Process(imgData) => val imgDataOut = filter.applyTo(imgData) next ! Process(imgDataOut) case Stop() => context.stop(self) } } Pattern matching

Slide 34

Slide 34 text

Actors: Akka Library 16 class Stage(filter: Filter, next: ActorRef) extends Actor { def receive = { case Process(imgData) => val imgDataOut = filter.applyTo(imgData) next ! Process(imgDataOut) case Stop() => context.stop(self) } } Pattern matching Case class

Slide 35

Slide 35 text

Actors: Akka Library 16 class Stage(filter: Filter, next: ActorRef) extends Actor { def receive = { case Process(imgData) => val imgDataOut = filter.applyTo(imgData) next ! Process(imgDataOut) case Stop() => context.stop(self) } } Pattern matching Infix call of “!” method Case class

Slide 36

Slide 36 text

Concurrent Programming Models as Libraries • Scala = “Scalable Language” • cf. Guy Steele. Growing a Language. OOPSLA ’98 keynote • Concurrent programming models as libraries • Based on shared-memory threads built into underlying virtual machine • Flexible extension and adaptation • Reuse of compilers, debuggers, and IDEs 17

Slide 37

Slide 37 text

Concurrent Programming Models as Libraries • Scala = “Scalable Language” • cf. Guy Steele. Growing a Language. OOPSLA ’98 keynote • Concurrent programming models as libraries • Based on shared-memory threads built into underlying virtual machine • Flexible extension and adaptation • Reuse of compilers, debuggers, and IDEs 17 Do not have to guess the answer to the question: Which concurrency model is going to “win”?

Slide 38

Slide 38 text

Experience • Authored or co-authored: • Scala Actors (2006) • Scala Joins (2008) • Scala futures (2012) • FlowPools (2012) • Scala Async (2013) • Contributions to Akka, Akka.js projects at Typesafe 18 Haller and Sommers Artima Press, 2012

Slide 39

Slide 39 text

Experience • Authored or co-authored: • Scala Actors (2006) • Scala Joins (2008) • Scala futures (2012) • FlowPools (2012) • Scala Async (2013) • Contributions to Akka, Akka.js projects at Typesafe 18 Haller and Sommers Artima Press, 2012 Production use at Twitter, The Guardian and others

Slide 40

Slide 40 text

Experience • Authored or co-authored: • Scala Actors (2006) • Scala Joins (2008) • Scala futures (2012) • FlowPools (2012) • Scala Async (2013) • Contributions to Akka, Akka.js projects at Typesafe 18 Haller and Sommers Artima Press, 2012 Production use at Twitter, The Guardian and others Production use at LinkedIn, The Huffington Post and others

Slide 41

Slide 41 text

Experience • Authored or co-authored: • Scala Actors (2006) • Scala Joins (2008) • Scala futures (2012) • FlowPools (2012) • Scala Async (2013) • Contributions to Akka, Akka.js projects at Typesafe 18 Haller and Sommers Artima Press, 2012 Production use at Twitter, The Guardian and others Production use at Morgan Stanley, Gawker and others Production use at LinkedIn, The Huffington Post and others

Slide 42

Slide 42 text

Experience • Authored or co-authored: • Scala Actors (2006) • Scala Joins (2008) • Scala futures (2012) • FlowPools (2012) • Scala Async (2013) • Contributions to Akka, Akka.js projects at Typesafe 18 Haller and Sommers Artima Press, 2012 Production use at Twitter, The Guardian and others Production use at Morgan Stanley, Gawker and others Production use at LinkedIn, The Huffington Post and others The programming-models-as-libraries approach has been successful in Scala!

Slide 43

Slide 43 text

Problem • Problem: Scala cannot ensure concurrency safety for library-based concurrency abstractions • This also applies to Java, C++, and most other widely-used programming languages 19

Slide 44

Slide 44 text

Revisiting the Example Image data apply filter Image processing pipeline: filter 1 filter 2 20 Pipeline stages run concurrently

Slide 45

Slide 45 text

Implementation 21

Slide 46

Slide 46 text

Implementation • Assumptions: • Main memory expensive (image data large) 21

Slide 47

Slide 47 text

Implementation • Assumptions: • Main memory expensive (image data large) • Approach for high performance: • In-place update of image buffers • Pass mutable buffers by-reference 21

Slide 48

Slide 48 text

Problem: Data Races Easy to produce data races: 1. Stage 1 sends a reference to a buffer to stage 2 2. Following the send, both stages have a reference to the same buffer 3. Stages can concurrently access the buffer 22

Slide 49

Slide 49 text

Preventing Data Races 23

Slide 50

Slide 50 text

Preventing Data Races • Approach: safe transfer of ownership • Sending stage loses ownership • Type system prevents sender from accessing transferred objects 23

Slide 51

Slide 51 text

Preventing Data Races • Approach: safe transfer of ownership • Sending stage loses ownership • Type system prevents sender from accessing transferred objects • Advantages: • No run-time overhead • Errors caught at compile time 23

Slide 52

Slide 52 text

Ownership Transfer in Scala 24

Slide 53

Slide 53 text

Ownership Transfer in Scala • Enter LaCasa: affine references for Scala 24

Slide 54

Slide 54 text

Ownership Transfer in Scala • Enter LaCasa: affine references for Scala • “Transferable” references 24

Slide 55

Slide 55 text

Ownership Transfer in Scala • Enter LaCasa: affine references for Scala • “Transferable” references • At most one owner per affine reference 24

Slide 56

Slide 56 text

Ownership Transfer in Scala • Enter LaCasa: affine references for Scala • “Transferable” references • At most one owner per affine reference • LaCasa combines two concepts: 24

Slide 57

Slide 57 text

Ownership Transfer in Scala • Enter LaCasa: affine references for Scala • “Transferable” references • At most one owner per affine reference • LaCasa combines two concepts: • Access permissions 24

Slide 58

Slide 58 text

Ownership Transfer in Scala • Enter LaCasa: affine references for Scala • “Transferable” references • At most one owner per affine reference • LaCasa combines two concepts: • Access permissions • Encapsulated boxes 24

Slide 59

Slide 59 text

Boxes • Boxes are encapsulated • Boxes must be opened for access 25

Slide 60

Slide 60 text

Boxes • Boxes are encapsulated • Boxes must be opened for access mkBox[Message] { packed => implicit val access = packed.access val box = packed.box box open { msg => msg.arr = Array(1, 2, 3, 4) } } 25

Slide 61

Slide 61 text

Boxes • Boxes are encapsulated • Boxes must be opened for access mkBox[Message] { packed => implicit val access = packed.access val box = packed.box box open { msg => msg.arr = Array(1, 2, 3, 4) } } Requires implicit access permission 25

Slide 62

Slide 62 text

Boxes • Boxes are encapsulated • Boxes must be opened for access mkBox[Message] { packed => implicit val access = packed.access val box = packed.box box open { msg => msg.arr = Array(1, 2, 3, 4) } } 25

Slide 63

Slide 63 text

Ownership Transfer mkBox[Message] { packed => implicit val access = packed.access val box = packed.box … someActor.send(box) { // `access` unavailable … } } 26

Slide 64

Slide 64 text

Practical Evaluation Empirical study of popular open source projects 27 Project #classes/traits #ocap (%) #dir. insec. (%) Scala stdlib 1,505 644 (43%) 212/861 (25%) Signal/Collect 236 159 (67%) 60/77 (78%) GeoTrellis -engine 190 40 (21%) 124/150 (83%) -raster 670 233 (35%) 325/437 (74%) -spark 326 101 (31%) 167/225 (74%) Total 2,927 1,177 (40%) 888/1,750 (51%)

Slide 65

Slide 65 text

Practical Evaluation Empirical study of popular open source projects 27 Project #classes/traits #ocap (%) #dir. insec. (%) Scala stdlib 1,505 644 (43%) 212/861 (25%) Signal/Collect 236 159 (67%) 60/77 (78%) GeoTrellis -engine 190 40 (21%) 124/150 (83%) -raster 670 233 (35%) 325/437 (74%) -spark 326 101 (31%) 167/225 (74%) Total 2,927 1,177 (40%) 888/1,750 (51%) > 75’000 LOC on GitHub

Slide 66

Slide 66 text

Practical Evaluation Empirical study of popular open source projects 27 Project #classes/traits #ocap (%) #dir. insec. (%) Scala stdlib 1,505 644 (43%) 212/861 (25%) Signal/Collect 236 159 (67%) 60/77 (78%) GeoTrellis -engine 190 40 (21%) 124/150 (83%) -raster 670 233 (35%) 325/437 (74%) -spark 326 101 (31%) 167/225 (74%) Total 2,927 1,177 (40%) 888/1,750 (51%) > 75’000 LOC on GitHub

Slide 67

Slide 67 text

Practical Evaluation Empirical study of popular open source projects 27 Project #classes/traits #ocap (%) #dir. insec. (%) Scala stdlib 1,505 644 (43%) 212/861 (25%) Signal/Collect 236 159 (67%) 60/77 (78%) GeoTrellis -engine 190 40 (21%) 124/150 (83%) -raster 670 233 (35%) 325/437 (74%) -spark 326 101 (31%) 167/225 (74%) Total 2,927 1,177 (40%) 888/1,750 (51%) “Ocap”: classes reusable without change > 75’000 LOC on GitHub

Slide 68

Slide 68 text

LaCasa: Types for Safe Concurrency in Scala 28

Slide 69

Slide 69 text

LaCasa: Types for Safe Concurrency in Scala • Ensure data-race safety statically via lightweight types • Sound integration with full Scala language • Minimize effort to reuse existing code:
 binary conformance check (yes/no) 28

Slide 70

Slide 70 text

LaCasa: Types for Safe Concurrency in Scala • Ensure data-race safety statically via lightweight types • Sound integration with full Scala language • Minimize effort to reuse existing code:
 binary conformance check (yes/no) • Recent paper:
 Haller and Loiko. LaCasa: Lightweight Affinity and Object Capabilities in Scala. OOPSLA 2016 28

Slide 71

Slide 71 text

LaCasa: Types for Safe Concurrency in Scala • Ensure data-race safety statically via lightweight types • Sound integration with full Scala language • Minimize effort to reuse existing code:
 binary conformance check (yes/no) • Recent paper:
 Haller and Loiko. LaCasa: Lightweight Affinity and Object Capabilities in Scala. OOPSLA 2016 • Ongoing:
 Empirical study on open source code corpus 28

Slide 72

Slide 72 text

LaCasa: Types for Safe Concurrency in Scala • Ensure data-race safety statically via lightweight types • Sound integration with full Scala language • Minimize effort to reuse existing code:
 binary conformance check (yes/no) • Recent paper:
 Haller and Loiko. LaCasa: Lightweight Affinity and Object Capabilities in Scala. OOPSLA 2016 • Ongoing:
 Empirical study on open source code corpus 28 Open source implementation: https://github.com/phaller/lacasa

Slide 73

Slide 73 text

Conclusion 29

Slide 74

Slide 74 text

Conclusion • Scala enables new concurrent programming methods 29

Slide 75

Slide 75 text

Conclusion • Scala enables new concurrent programming methods • Scala enables library extensions providing new concurrent programming models • Building on concurrency support of underlying runtime platform 29

Slide 76

Slide 76 text

Conclusion • Scala enables new concurrent programming methods • Scala enables library extensions providing new concurrent programming models • Building on concurrency support of underlying runtime platform • Scalability and performance enable wide use in large- scale production systems 29

Slide 77

Slide 77 text

Conclusion • Scala enables new concurrent programming methods • Scala enables library extensions providing new concurrent programming models • Building on concurrency support of underlying runtime platform • Scalability and performance enable wide use in large- scale production systems • Lightweight type system extensions are being developed to ensure concurrency safety 29

Slide 78

Slide 78 text

Conclusion • Scala enables new concurrent programming methods • Scala enables library extensions providing new concurrent programming models • Building on concurrency support of underlying runtime platform • Scalability and performance enable wide use in large- scale production systems • Lightweight type system extensions are being developed to ensure concurrency safety 29 Thank you!