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

Programming with Futures, Lattices, and Quiescence

Philipp Haller
June 16, 2016
580

Programming with Futures, Lattices, and Quiescence

Philipp Haller

June 16, 2016
Tweet

More Decks by Philipp Haller

Transcript

  1. Programming with Futures,
    Lattices, and Quiescence
    Philipp Haller
    KTH Royal Institute of Technology
    Sweden
    @philippkhaller
    1

    View Slide

  2. 2

    View Slide

  3. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Have we solved concurrent programming, yet?
    There are promising concurrent programming models
    and abstractions!
    3
    • Monitors
    • Futures, promises
    • Async/await
    • STM
    • Actors
    • Join-calculus
    • Agents
    • CSP
    • Reactive streams
    • …

    View Slide

  4. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Background
    • Authored or co-authored:
    – Scala Actors
    – Scala futures and promises
    – Scala Async
    • Contributed to Akka
    • Akka.js project at Typesafe
    4
    More proposals and
    research projects:
    •Scala Joins
    •FlowPools
    •Spores
    ..

    View Slide

  5. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Why are there so many?
    The problem with concurrency:
    – It’s difficult!
    – Multiple hazards:
    • Race conditions
    • Deadlocks
    • Livelocks
    • Violation of fairness
    5

    View Slide

  6. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Non-Determinism
    • At the root of several hazards
    • Example 1:
    6
    @volatile var x = 0
    def m(): Unit = {
    Future {
    x = 1
    }
    .. // does not access x
    x = 2
    }
    What’s the value of x
    • when m returns?
    • when the future is
    completed?

    View Slide

  7. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Non-Determinism
    • At the root of several hazards
    • Example 2:
    7
    @volatile var x = 0
    def m(): Unit = {
    Future {
    x = 1
    }
    Future {
    x = 2
    }
    .. // does not access x
    }
    What’s the value of x
    • when m returns?
    • when the futures
    are completed?

    View Slide

  8. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Reordering not always a problem!
    • Example 3:
    8
    import scala.collection.concurrent.TrieMap
    val set = new TrieMap[Int, Int]
    Future {
    set.put(1, 0)
    }
    set.put(2, 0)
    Eventually, set contains
    both 1 and 2, always
    Bottom line: it depends on the datatype

    View Slide

  9. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    … and its operations!
    • Example 4:
    9
    val set = new TrieMap[Int, Int]
    Future {
    set.put(1, 0)
    }
    Future {
    if (set.contains(1)) {
    ..
    }
    }
    set.put(2, 0)
    Result depends
    on schedule!

    View Slide

  10. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Important questions
    Q1:

    How do we know we have written a deterministic
    concurrent program?
    – What about Heisenbugs?
    • No race in 1’000’000 runs, race in run 1’000’001
    10
    Goal: simple criteria that guarantee determinism

    View Slide

  11. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Important questions
    Q2:

    How do we ensure expressivity while providing
    determinism?
    – Draconian restrictions undesired!
    11
    Goal: reconcile determinism and expressivity

    View Slide

  12. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Approach
    • Extend futures and promises with:
    – Lattice-based operations
    – Quiescence
    – Resolution of cyclic dependencies
    • Evaluation in terms of expressivity and performance
    – Case study: static analysis of JVM bytecode
    12
    Crucial for
    determinism!
    Increases
    expressivity!

    View Slide

  13. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Enter Reactive Async
    Programming model based on two core abstractions:

    cells and cell completers
    – Cell[K,V] extends Future[V]
    – CellCompleter[K,V] extends Promise[V]
    – V must have an instance of a lattice type class
    • Monotonic updates
    13

    View Slide

  14. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Example
    • Given a social graph
    – vertex = user
    • Traverse graph and collect IDs of “interesting” users
    • Graph large => concurrent traversal
    14

    View Slide

  15. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Solution
    • Collect IDs of interesting users in a cell
    • Cell contains set of integers
    15
    OK: subsets of the set of
    all integers form a lattice

    View Slide

  16. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Cell with user IDs
    (code simplified)
    16
    implicit object IntSetLattice extends Lattice[Set[Int]] {
    val empty = Set()
    def join(left: Set[Int], right: Set[Int]) = left ++ right
    }
    // add a user ID
    userIDs.putNext(Set(theUserID))
    val userIDs = CellCompleter[Set[Int]]
    Bounded

    join-semilattice

    View Slide

  17. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Reading the result
    • Problem: when reading a cell’s value, how do we
    know this value is not going to change any more?
    – There may still be ongoing concurrent activities
    – Manual synchronization (e.g., latches) error-prone
    • Solution:
    17
    Koyaanisqatsi
    Quiescence

    View Slide

  18. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Quiescence
    • Intuitively: situation when values of cells are
    guaranteed not to change any more
    • Technically:
    – No concurrent activities ongoing or scheduled
    which could change values of cells
    – Detected by the underlying thread pool
    18

    View Slide

  19. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Revisiting the example
    19
    // add a user ID
    userIDs.putNext(Set(theUserID))
    ..
    val pool = new HandlerPool
    val userIDs = CellCompleter[Set[Int]](pool)
    // register handler
    // upon quiescence: read result value of cell
    pool.onQuiescent(userIDs.cell) { collectedIDs =>
    ..
    }
    Safe to read
    from cell when pool
    quiescent!

    View Slide

  20. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Handler pools
    Execution context with extensions:
    – Event-driven quiescence API
    – Resolution of dependencies between cells
    20
    Dependency resolution?

    View Slide

  21. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Expressing concurrent dataflow
    • Cells provide non-blocking interface
    – Low level: callbacks
    – High level: combinators
    • Important purpose: express concurrent dataflow
    • Problem:
    21
    What if the dataflow graph is cyclic?
    Like futures
    fut
    fun
    fut’
    pred
    fut’’
    fut.map(fun).filter(pred)
    Futures

    View Slide

  22. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Dataflow graphs
    Example:
    • Static analysis of JVM bytecode
    • Task:

    Determine purity of methods
    • Rules:
    – A method is impure if it accesses a non-final field
    – A method is impure if it calls an impure method
    – …
    22
    A B
    C
    “calls”

    View Slide

  23. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Cycle resolution
    • What if upon quiescence cells are empty and there is a
    dependency cycle?
    • Idea:

    Pluggable resolution policies
    • Example:

    Purity analysis should resolve all cells

    in cycle to “pure”, since could not show impurity
    23
    A B
    C

    View Slide

  24. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Specifying resolution policies
    • Role of the first type parameter of Cell[K,V]
    • Example:
    24
    object PurityKey extends Key[Purity] {
    def resolve[K cells.map(cell => (cell, Pure))
    ..
    }
    closed strongly-
    connected component
    resolve all
    cells to Pure

    View Slide

  25. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Purity analysis: set up
    25
    for {
    classFile method } {
    val methodCompleter = CellCompleter(pool, PurityKey)
    pool.execute {
    analyze(project, methodCompleter, classFile, method)
    }
    }
    val analysisDoneFuture = pool.quiescentResolveCells()

    View Slide

  26. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Evaluation
    • Static analysis of JVM bytecode using the OPAL
    framework (OPen extensible Analysis Library)
    – Newly developed, highly adaptable bytecode toolkit
    – Fully concurrent
    • Rewrote purity analysis and immutability analysis
    • Ran analysis on JDK 8 (rt.jar)
    – 18’591 class files, 163’268 methods, 77’128 fields
    26
    http://www.opal-project.de

    View Slide

  27. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Preliminary results
    • RA’s implementation not yet optimized
    27
    RA 15% faster than OPAL’s implementation with
    • code size reduced by a factor of two
    • determinism properties

    View Slide

  28. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Ongoing and future work
    • Benchmarking and optimization
    • Determinism as an effect
    – Determinism guaranteed by type checker
    – Effect system for Dotty
    • Macro support à la Async?
    28

    View Slide

  29. Programming with Futures, Lattices, and Quiescence — Philipp Haller
    Reactive Async: conclusion
    • New concurrent programming model
    – Lattices and quiescence for determinism
    – Resolution of cyclic dependencies
    • Promising preliminary results
    • Future: static checking of determinism via effects
    29
    https://github.com/phaller/reactive-async
    Thank you!

    View Slide

  30. 30

    View Slide

  31. 31

    View Slide