• 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 ..
are there so many? The problem with concurrency: – It’s difficult! – Multiple hazards: • Race conditions • Deadlocks • Livelocks • Violation of fairness 5
• 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?
• 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?
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
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!
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
questions Q2: How do we ensure expressivity while providing determinism? – Draconian restrictions undesired! 11 Goal: reconcile determinism and expressivity
• 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!
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
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
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
• 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
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!
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
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”
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
resolution policies • Role of the first type parameter of Cell[K,V] • Example: 24 object PurityKey extends Key[Purity] { def resolve[K <: Key[Purity]](cells: Seq[Cell[K, Purity]]) = cells.map(cell => (cell, Pure)) .. } closed strongly- connected component resolve all cells to Pure
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
and future work • Benchmarking and optimization • Determinism as an effect – Determinism guaranteed by type checker – Effect system for Dotty • Macro support à la Async? 28
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!