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

Safe and Scalable Concurrent Programming in Scala

Philipp Haller
December 01, 2016
280

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

    View Slide

  2. Programming a Concurrent World
    2

    View Slide

  3. Programming a Concurrent World
    • How to compose programs handling
    2

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  8. 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

    View Slide

  9. 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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  15. Concurrent
    Programming in Scala
    6

    View Slide

  16. Example
    Image
    data
    7

    View Slide

  17. Example
    Image
    data
    apply filter
    7

    View Slide

  18. Example
    Image
    data
    apply filter
    7

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  22. 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 =>
    // ..
    }

    View Slide

  23. 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?

    View Slide

  24. 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)
    }
    }

    View Slide

  25. Is this all built into
    Scala?
    12

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  31. 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

    View Slide

  32. 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)
    }
    }

    View Slide

  33. 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

    View Slide

  34. 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

    View Slide

  35. 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

    View Slide

  36. 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

    View Slide

  37. 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”?

    View Slide

  38. 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

    View Slide

  39. 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

    View Slide

  40. 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

    View Slide

  41. 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

    View Slide

  42. 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!

    View Slide

  43. 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

    View Slide

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

    View Slide

  45. Implementation
    21

    View Slide

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

    View Slide

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

    View Slide

  48. 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

    View Slide

  49. Preventing Data Races
    23

    View Slide

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

    View Slide

  51. 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

    View Slide

  52. Ownership Transfer in Scala
    24

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  57. 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

    View Slide

  58. 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

    View Slide

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

    View Slide

  60. 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

    View Slide

  61. 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

    View Slide

  62. 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

    View Slide

  63. Ownership Transfer
    mkBox[Message] { packed =>
    implicit val access = packed.access
    val box = packed.box

    someActor.send(box) {
    // `access` unavailable

    }
    }
    26

    View Slide

  64. 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%)

    View Slide

  65. 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

    View Slide

  66. 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

    View Slide

  67. 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

    View Slide

  68. LaCasa: Types for Safe
    Concurrency in Scala
    28

    View Slide

  69. 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

    View Slide

  70. 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

    View Slide

  71. 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

    View Slide

  72. 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

    View Slide

  73. Conclusion
    29

    View Slide

  74. Conclusion
    • Scala enables new concurrent programming methods
    29

    View Slide

  75. 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

    View Slide

  76. 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

    View Slide

  77. 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

    View Slide

  78. 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!

    View Slide