Csp scala wixmeetup2016
-
Upload
ruslan-shevchenko -
Category
Software
-
view
777 -
download
0
Transcript of Csp scala wixmeetup2016
Wix R&D meetup;
CSP & Scala: theory and implementation. https://github.com/rssh/scala-gopher
Ruslan Shevchenko<[email protected]>
https://github.com/rssh
@rssh1
2. Outline❖ Theory & History
❖ CSP = Communication Sequence Processes
❖ !-calculus (CCS = Calculus of Communicating System)
❖ Languages: (Occam,Limbo, Go[Clojure, Scala, … ])
❖ Main constructions / idioms, how they looks
❖ Channels, Selectors, Transputers
❖ Implementation Techniques
3. Theory & History
❖ If you familiar with basic concepts, skip to slide 8
❖ Just show me scala API: skip to slide 14
4. Theory & History❖ CPS = Communication Sequence Processes.
❖ CSS = Calculus of Communicating System.
❖ 1978 First CSP Paper by Tony Hoar.
❖ 1980. CSS by Robert Milner. (Algebraic Processes)
❖ 1985 CSP formalism (influenced by CSS) in CSP Book
❖ http://www.usingcsp.com/
❖ 1992 !-calculus [CSS + Channels] (Robert Milner, Joachim Parrow, David Walker)
❖ …. (large family of Process Algebras, including Actor Model, ACP, )
5. CSP Notation(basic)
❖ (A, B, C … ) — processes,
❖ (x, y, z … ) — events
❖ atomic: x , STOP, BEEP, or c.v (channel/value)
❖ c!v - send v to channel c (after this c.v happens)
❖ c?v - receive v from channel c (wait until c.v)
❖ trace(…) — sequence of events.
6. CSP Notation(basic)
// after event
Operations on processes:
// fix point (loops, recursion)
// interleave concurrently
// choice, if a then P if b then Q
// seq
8. Occam language
William Occam, 1287-1347‘Occam razor’ principle
Occam language. (1983)
INT x, y: SEQ x := 4 y := (x + 1) CHAN INT c: PAR some.procedure (x, y, c!) another.procedure (c?) y := 5
braces via indentation. (before python)
minimal language. (processor constructors)
9. Occam language
❖ created by INMOS
❖ targeted Transputers CHIP architecture (bare metal)
❖ latest dialect: occam-! [1996]
❖ extensions from !-calculus
❖ (more dynamic, channels can be send via channels)
❖ http://concurrency.cc — occam for Aurdino.
10. Inferno, Limbo, Go❖ Unix, Plan9, Inferno: [At&t; Bell labs; vita nuova]
❖ http://www.vitanuova.com/inferno/
❖ Limbo … C-like language + channels + buffered channels.
❖ Go … channels as in Limbo (Go roots is from hell is not a metaphor)
Sean ForwardDavid Leo PresottoRob PikeDennis M. RitchieKen Thompson
11. CPS in Limbo/Go/Scala: main constructions
❖ processes: operator for spawning new lightweight process.
❖ channels: can be unbuffered (synchronised) or buffered
❖ unbuffered — writer wait until reader start to work
❖ buffered — if channel buffer is not full, writer not blocked
❖ selector: wait for few events (channel), eval first.
12. Go: simple code examplefunc fibonacci(c chan int, quit chan bool) { go {
x, y := 0, 1for (){
select {case c <- x : x, y = y, x+y
case q<-quit: break; }
}close(c)
}}
c = make(chan int);quit= make(chan bool);fibonacci(c,quit)for i := range c {
fmt.Println(i) if (i > 2000) { quit <- true }}
Go
13. Go: simple code examplefunc fibonacci(c chan int, quit chan bool) { go {
x, y := 0, 1for (){
select {case c <- x : x, y = y, x+y
case q<- quit: break; }
}close(c)
}}
c = make(chan int);quit= make(chan bool);fibonacci(c,quit)for i := range c {
fmt.Println(i) if (i > 2000) { quit <- true }}
Go
14. scala-gopher
❖ Akka extension + Macros on top of SIP22-async
❖ Integrate CSP primitives and scala concurrency
❖ Provide:
❖ asynchronous API inside general control-flow
❖ pseudo-synchronous API inside go{ .. } or async{ ..} blocks
def fibonacci(c: Channel[Int], quit: Channel[Boolean]): Future[Unit] = go {var (x, y) = (0, 1)select.forever{
case x : c.write => val z = x
x = y; y = x+z case q: quit.read => CurrentFlowTermination.exit(())
}c.close()
}
15. Scala: simple code example (direct translation)
val c = makeChannel[Int]()val quit= makeChannel[Boolean]();val f = fibonacci(c,quit)for ( i <- c) {
System.out.print(i) if (i > N) { quit.awrite( true ) }
Scala
16. Scala-gopher: main constructions❖ Gopher: Akka extension.
❖ go[T](body: T): Future[T]
❖ inside body we can use pseudosynchronous API
❖ defer
❖ select [forever, once] => [choice]
❖ case matching macros; for statement, fold, ..
❖ channels
❖ channels/ Input[X]/Output[X] / collection API
val gopherApi = GopherAPI(actorsSystem)import gopherApi._
def fibonacci(c: Channel[Int], quit: Channel[Boolean]): Future[Unit] = go {var (x, y) = (0, 1)select.forever{
case x : c.write => val z = x
x = y; y = x+z case q: quit.read => CurrentFlowTermination.exit(())
}c.close()
}}
17. Scala: simple code example (direct translation)
val c = makeChannel[Int]()val quit= makeChannel[Boolean]();val f = fibonacci(c,quit)for ( i <- c) {
System.out.print(i) if (i > N) { quit.awrite( true ) }
Scala
(mutable var, WTF ?)
def fibonacci(c: Channel[Int], quit: Channel[Boolean]): Future[Unit] = go { select.fold((0,1)){ case ((x,y),s) =>
s match {case x : c.write => (y, x+y)
case q: quit.read => CurrentFlowTermination.exit((x,y)) }
}c.close()
}
18. Scala: simple code example (fold)
val c = makeChannel[Int]()val quit= makeChannel[Boolean]();val f = fibonacci(c,quit)for ( i <- c) {
System.out.print(i) if (i > N) { quit.awrite( true ) }
Scala
def fibonacci(c: Channel[Int], quit: Channel[Boolean]): Future[Unit] = go { val (x,y) = select.fold((0,1)){ case ((x,y),s) =>
s match {case x : c.write => (y, x+y)
case q: quit.read => CurrentFlowTermination.exit((x,y)) }
}c.close()
}
19. Scala: simple code example (fold)
val c = makeChannel[Int]()val quit= makeChannel[Boolean]();val f = fibonacci(c,quit)for ( i <- c) {
System.out.print(i) if (i > N) { quit.awrite( true ) }
Scala
def fibonacci(c: Channel[Int], quit: Channel[Boolean]): Future[(Int,Int)] = select.afold((0,1)){ case ((x,y),s) =>
s match {case x : c.write => (y, x+y)
case q: quit.read => c.close() CurrentFlowTermination.exit((x,y)) }
}
20. Scala: simple code example (аfold)
val c = makeChannel[Int]()val quit= makeChannel[Boolean]();val f = fibonacci(c,quit)for ( i <- c) {
System.out.print(i) if (i > N) { quit.awrite( true ) }
Scala
s match {case x : c.write => (y, x+y)
case q: quit.read => c.close() CurrentFlowTermination.exit((x,y)) }
21. scala-gopher: select Scala
s match { case z : c.write if (z == 1) => …….. case x: Int if (x == future.read()) => }
//special syntax
//writing expressions
//reading from expressions
22. scala-gopher: select de-‘macro’select.forever{ case x: channel1.read => (do-something-1) case y: channel2.read => (do-something-2) case z: channel3.write => (do-something-3) case _ => (do-somethig-4)}
{ val s = select.createForeverSelectorBuilder() s.reading(channel1, x => (do-something-1)) s.reading(channel2, y => (do-something-2)) s.write(channel3,z,….) s.idle(do-something-4) s.run() }
23. scala-gopher: select de-‘macro’
s.reading(channel1, x => (do-something-1))
s.onRead(channel1, x => { implicit f1: FlowTermination = s.flowTermination implicit e1: ExecutionContext => s.executionContext scala.async.Async.async( transfer(do-something-1) )}
24. scala-gopher: select functionality
❖ select functionality
❖ wrap callbacks, supplied by user
❖ to guarantee than only one branch of select match is running
❖ to provide reaction on flowTermination
❖ pass one to channels/inputs/outpus
25. scala-gopher: Input/Output.❖ Input[T] - something, from which we can wait input
❖ callback-based ‘native’ trait.
❖ implementations: channels, futures, collections …
❖ collection-like methods: map, filter, fold, zip, append, merge…
aread(): Future[T]
read: T = await(aread)
<~ = read.
26. scala-gopher: Input/Output.❖ Output[T] - something, where we can send value
❖ callback-based ‘native’ trait.
❖ implementations: channels, promises, actor-s…
awrite(v:T): Future[T]
write(t): T = await(awrite(t))
~> = write.
27. scala-gopher: Timeoutsval (in, inTimeouts) = in.withTimeout(1 minute)val (out, outTimeouts) = out.withTimeout(10 minutes)
select.fold(s0){ (state,selector) => selector match { case x: in.read => out.write(x) case t: inTimeouts.read => log(“input timeout”); case t: outTimeouts.read => log(“output timeout”); }}
28. Example: broadcast without listener registry
❖ Sender:
❖ create buffered channel for each message
❖ send into this channel: message + channel for next message
❖ can report value of channel for next message
❖ Receiver:
❖ read message from channel,
❖ put one back (to allow other readers to receive one)
❖ change channel to listen on just receive.
29. Example: broadcast without listener registrycase class Message[V]( value: Value, nextChannel: Channel[Message[V]])
class Receiver[V](initChannel: Message, handle: V => Unit){ val current = makeEffectedChannel(initChannel) val future = current.forever{ message => current write message.value current := message.nextChannel go { handle(message.value) } }}
30. Example: broadcast without listener registry
class Broadcaster[V]() // single-threaded{ var last = makeNextChannel def send(v: V) : Unit = { val next = makeNextChannel last write Message(v, next) last = next }
def makeReceiver(handler: V => Unit) = new Receiver(current, next)
def makeNextChannel = makeChannel[Message[V]](1)}
31. Example: broadcast without listener registry
class Broadcaster[V]() { val sendc = makeChannel[V]() val requestLast = makeChannel[Channel[Channel[Value[V]]]()
val future = select.fold(makeNextChannel){ (last,s) => s match { case v:sendc.read => val next = makeNextChannel last <~ Message(v,next) next case r:requestLast.read => r <~ last last } } def send(v: V) : Unit = sendc.send(v)
31. Example: broadcast without listener registry
class Broadcaster[V]() { val sendc = makeChannel[V]() val requestLast = makeChannel[Channel[Channel[Value[V]]]()
val future = select.fold(makeNextChannel){ (last,s) => s match { case v:sendc.read => val next = makeNextChannel last <~ Message(v,next) next case r:requestLast.read => r <~ last last } }
def makeReceiver(handler): Future[Receiver] = go { val r = makeChannel[Channel[Message[V]] requestLast <- r Receiver(await(r.read),handler) }
33. CPS / Scala
❖ Test of
❖ essential CPS functionality
❖ dynamic channels
❖ state inside selector folds
❖ More : Transputers
34. Transputers❖ Structure => schemes.
❖ Entity,
❖ set of input ports
❖ set of output ports
❖ logic
❖ Process/Transputer
35 Transputers.trait Bingo extends Transputer{ val inX = inPort[Int]() val inY = inPort[Int]() val out = OutPort[String]()
loop { case x: inX.read => val y = inY.read if (x == y) { out <~ “Bingo!” } }}
36. Transputers❖ like actors, but for channels
❖ can be supervised ‘as actors’.
❖ can be connected to each other
val (inX,inY) = (makeChannel[Int](), makeChannel[Int])val bing = makeTransputer[Bingo]val acceptor = makeTransputer[Acceptor]bingo.inX connect inXbingo.inY connect inYbingo.out connect acceptor(bingo + acceptor).start()
38. Scala concurrency ecosystem
❖ Future [?]
❖ Erlang-Style ? (actors)
❖ Ozz-Style ? (async [partially])
❖ CPS (gopher)
❖ Rx [?]
❖ Can be used together.
39. Scala-Gopher, problems
❖ async implementation
❖ (buggy, not complete)
❖ need application programmer use macros for providing ‘pseudo synchronised’ API
❖ Need more experience.
❖ // details will be in ScalaUA talk.
40. Questions?
❖ It was about: https://github.com/rssh/scala-gopher
❖ Questions ?
❖ Thanks for attention.