Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Safe and Scalable Concurrent Programming in Scala

Philipp Haller
December 01, 2016
420

Safe and Scalable Concurrent Programming in Scala

Philipp Haller

December 01, 2016
Tweet

Transcript

  1. 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
  2. Programming a Concurrent World • How to compose programs handling

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

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

    • asynchronous events? • streams of asynchronous events? • distributed events? ➟ Programming abstractions for concurrency! 2
  5. 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
  6. 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
  7. Futures 8 val imgData: Buffer = .. val filter: Filter

    = .. val futImgData = Future { filter.applyTo(imgData) } futImgData.foreach { imgDataOut => // .. }
  8. Futures: Two Filters 9 val futImgDataOut1 = Future { filter1.applyTo(imgData)

    } val futImgDataOut2 = futImgDataOut1.map { imgDataOut1 => filter2.applyTo(imgDataOut1) } futImgDataOut2.foreach { imgDataOut2 => // .. }
  9. 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 => // .. }
  10. 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?
  11. 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) } }
  12. Futures 13 val imgData: Buffer = .. val filter: Filter

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

    = .. val futImgData: Future[Buffer] = Future.apply[Buffer]({ filter.applyTo(imgData) }) futImgData.foreach { imgDataOut => // .. }
  14. Futures Creating a future: 15 object Future { def apply[T](body:

    => T): Future[T] } Singleton object Generic type parameter
  15. 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
  16. 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) } }
  17. 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
  18. 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
  19. 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
  20. 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
  21. 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”?
  22. 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
  23. 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
  24. 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
  25. 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
  26. 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!
  27. 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
  28. Revisiting the Example Image data apply filter Image processing pipeline:

    filter 1 filter 2 20 Pipeline stages run concurrently
  29. Implementation • Assumptions: • Main memory expensive (image data large)

    • Approach for high performance: • In-place update of image buffers • Pass mutable buffers by-reference 21
  30. 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
  31. Preventing Data Races • Approach: safe transfer of ownership •

    Sending stage loses ownership • Type system prevents sender from accessing transferred objects 23
  32. 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
  33. Ownership Transfer in Scala • Enter LaCasa: affine references for

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

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

    Scala • “Transferable” references • At most one owner per affine reference • LaCasa combines two concepts: 24
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. Ownership Transfer mkBox[Message] { packed => implicit val access =

    packed.access val box = packed.box … someActor.send(box) { // `access` unavailable … } } 26
  42. 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%)
  43. 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
  44. 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
  45. 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
  46. 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
  47. 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
  48. 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
  49. 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
  50. 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
  51. 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
  52. 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
  53. 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!