SlideShare a Scribd company logo
1 of 70
Download to read offline
N FLAVORS OF
STREAMING
// Current landscape & ideas
Ruslan Shevchenko <ruslan@shevchenko.kiev.ua>
https://github.com/rssh
@rssh1
N FLAWORS OF STREAMING
- main ideas
// from board-based micro-optimizations to distributed computing
- most notable implementations
- programming languages
- Sisal //Streaming, DEC, Occam //CSP origin, INMOS Limbo Go //Unix/Plan9
Inferno Traditions, ,Elm //FRP generalization ,Orc //channel-based , etc…
- scala implementations
(iteratee/enumeratee, scalaz-streams,fs2, akka-streams, gopher, monix.io, etc ….)
- scala-gopher: state and news.
- Timed stream of data [or stream processor] as language
entity
- Combinators
- Data flow, orthogonal to Control flow
When person device is tracked in retail store,
sometimes,
send him message from pizzeria with
discount on his/she favorite food.
When connect to wifi
show personalized advertising
// Q: why ? - let’s model
STREAMING : WHERE IS GAIN ?
locationRequests.foreach{ r =>
ctx.saveRequest(r)
for{deviceId <- ctx.retrieveDeviceId(r)
profile <- ctx.findProfile(deviceId) if (profile.eligibleToSend)
message <- prepareMessage(profile)
} {
ctx.send(message)
cts.saveAction(profileData.id,message,now)
}
}
// traditional approach (pseudocode)
STREAMING : WHERE IS GAIN ?
locationRequests.foreach{ r =>
ctx.saveRequest(r)
for{deviceId <- ctx.retrieveDeviceId(r)
profile <- ctx.findProfile(deviceId) if (profile.eligibleToSend)
message <- prepareMessage(profile)
} {
ctx.send(message)
cts.saveAction(profileData.id,message,now)
}
}
// traditional approach (pseudocode)
val graph = locationTracking.tee(db.save).amap( ctx.retrieveDevice ).
amap( ctx.findProfille ).
filter{ _.eligibleToSend }.
amap(prepareMessage).
tee(ctx.send).sink(ctx.saveAction)
graph.run()
// streaming approach (pseudocode)
MORE COMPLEX EXAMPLE - SHOW ADS ON REQUEST
When person device is tracked in retail store,
Then when h/she connect to wifi
show personalized advertising
SHOW ADS ON REQUEST
// traditional approach (pseudocode)
locationTracking.foreach(r =>
for(deviceId <- ctx.retrieveDevice)
db.save(deviceId, r.placement)
)
adRequest.foreach( r ->
for( device <- ctx.retrieveDevice
placement <- db.retrievePlacements(device, 10 min)
profile <- findProfile(deviceId) if (profile.eligibleToAd)
advertising <- createAdvertising(profile)
) yield advertising
)
WE NEED STATE
// traditional approach (pseudocode)
locationTracking.foreach(r =>
for(deviceId <- ctx.retrieveDevice)
db.save(deviceId, r.placement)
)
adRequest.foreach( r ->
for( device <- ctx.retrieveDevice
placement <- db.retrievePlacements(device, 10 min)
profile <- findProfile(deviceId) if (profile.eligibleToAd)
advertising <- createAdvertising(profile)
) yield advertising
)
NO EXPLICIT STATE
// traditional approach (pseudocode)
locationTracking.foreach(r =>
for(deviceId <- ctx.retrieveDevice)
db.save(deviceId, r.placement)
)
adRequest.foreach( r ->
for( device <- ctx.retrieveDevice
placement <- db.retrievePlacements(device, 10 min)
profile <- findProfile(deviceId) if (profile.eligibleToAd)
advertising <- createAdvertising(profile)
) yield advertising
)
STATE
val deviceLocations = locationTracking.retrieveDevice
val ads = adRequests.amap(retrieveDevice)
.crossBy(deviceLocations, 10 min)(_.placement)
.amap(findProfile(deviceId)filter(_.eligibleToAd)
amap(ctx.createAdvertising)
graph(deviceLocations,ads).run
(state is an implementation detail of
deviceLocations stream. [crossBy ]
STREAM-BASED API:
• Hight level
• Save thinking about state
• Incapsulate effects into stream
F:A=>B
S MAM F: S[A] => S[B]
• Persistent
• Distributed
• Monitored …….
• Deferred…
HISTORY
SISAL: 1983 (Michigan University)
- imperative function language; implicit parallelism
type ints = stream[integer]
function Filter(S: ints, M: Integer return Ints)
for I in S
return stream of I unless mod(i,m)=0
end for
end function
function Integers (return Ints)
for initial
I:=3
while true repeat
I:= old I + 2
return stream of I
end for
function PrimesUpTo(Limit: Integer return Ints)
let maxs := integer(sqrt(real(Liimit)) in
for initial
D:=Integer(), t:=2
while T < Limit repeat
T := first(old S)
S: = if T < S Filter(rest(old S), T)
Else rest(old S) endif
return stream of T
end for
end let
end function
HISTORY: SISAL
SISAL: 1983 (Michigan University)
- implicit parallelism,
- imperative function language
- outperform Fortran in some cases
- direct descendant in today-s language:
CUDA kernel functions in Nvidia GPU
__global__ void vecAdd(double *a, double *b, double *c, int n)
{
int id = blockIdx.x*blockDim.x+threadIdx.x;
// Make sure we do not go out of bounds
if (id < n)
c[id] = a[id] + b[id];
}
vecAdd<<<dimGrid, dimBlock>>>(ad, bd);
HISTORY: CSP
❖ 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, )
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)
History: Occam
❖ 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 Arduino.
History: Occam
History: 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 Forward
David Leo Presotto
Rob Pike
Dennis M. Ritchie
Ken Thompson
13. Go: simple code example
func bonacci(c chan int, quit chan bool) {
go {
x, y := 0, 1
for (){
select {
case c <- x :
x, y = y, x+y
case q<- quit:
break;
}
}
close(c)
}
}
c = make(chan int);
quit= make(chan bool);
bonacci(c,quit)
for i := range c {
fmt.Println(i)
if (i > 2000) {
quit <- true
}
}
Go
ORC:
University of Texas, Augustin.
2009 - ….
All values are streaming, all calls are concurrent
Concurrency combinators:
• A | B (parallel execution)
• {| A |} (wait until first value will arrive in a)
• A; B (A then B )
• A > x > B (spawn B on each value from x from A)
• A>>B (if we need no x value).
Orc Example:
def min((n1,q1), (n2,q2)) =
    Ift(q1 <= q2) >> (n1, q1)
  | Ift(q2 <: q1) >> (n2, q2)
-- Return the best quote at or under $200
-- received within 15 seconds
def bestQuote([]) = ("None of the above", 200)
def bestQuote(airline:rest) =
    val best = bestQuote(rest)
    val current = airline() | Rwait(15000) >> best
    min(current, best)
bestQuote([Airline("Delta"),
           Airline("United")])
Scala: Lets’ emulate all N flavors.
❖ Foundations:
❖ Functional (std libs, scalaz-streams, fs2, .. spark)
❖ Rx (akka-streams, monix)
❖ CSP (scala-gopher, subscript)
❖ Implementations:
❖ Pull (scalaz-streams, fs2, Rx cold)
❖ Push [+ flow control] (akka, Rx hot)
❖ Active-Channels (gopher)
Functional Streaming: Ideas:Pull
❖ Pull
❖ step 0 (std: scala: provide generation function,
which called on reading element)
❖ step 1 (next element => (element | end | error))
❖ step 2 - emit more than one element (called function
return element generator)
❖ step 3 - combine and add pull generator.
Functional Streaming: Ideas:Pull
❖ Pull
❖ step 0 (std: scala: provide generation function,
which called on reading element)
❖ step 1 (next element => (element | end | error))
❖ step 2 - emit more than one element (called function
return element generator)
❖ step 3 - combine and add pull generator.
SNil
::: ( => T)
def gen(n):Stream[Int] =
{
n :: gen(n+1)
}
Functional Streaming: :Pull
❖ Pull
❖ step 1 (next element => (element | end | error))
❖ step 2 - emit more than one element (called function
return element generator)
SNil sealed trait Out[-T]
::: ( => Out[T] ) Error, End, Element[T]
def gen(n,m):Stream1[Int] =
{
if (n==m) End else n ::: gen(n+1)
}
Functional Streaming: Ideas:Pull
❖ Pull
❖ step 2 - emit more than one element (called function
return element)
❖ t generator)
SNil trait Pull
::: ( => Pull[T] ) Pull.error, Pull.end,
Pull.emit(t1, t2)
Pull.flatMap(otherPull)
Functional Streaming: Ideas:Pull
❖ Pull
❖ step 3 — wrap output in a monad [ usually: Task ]
❖ t generator)
SNil trait Pull
::: ( => Pull[M,T,S] ) Pull.error, Pull.end[S],
Pull.emit(t1, t2)
Pull.flatMap(otherPull)
stream.run
stream.eval(…)
Functional Streaming: Ideas:Pull
❖ Pull
❖ step N — pull combinators running in transformer.
❖ t generator)
+ states,
+ stream combinators
def nextS(n: Int, f: (Int) => Boolean):fs2.Stream[Pure, Int] = {
if (f(n))
fs2.Stream(n) ++ nextS(n+1, x => f(x) && x % n != 0)
else
nextS(n+1, f)
Functional Streaming: Ideas:Pull
❖ Pull problem: need to know computation semantics exactly
❖ t generator)
def simple(from: Int): fs2.Stream[Pure, Int] =
fs2.Stream(from) ++ simple(from + 1).lter(n => n % from!= 0)
def nextS(n: Int, f: (Int) => Boolean):fs2.Stream[Pure, Int] = {
if (f(n))
fs2.Stream(n) ++ nextS(n+1, x => f(x) && x % n != 0)
else
// easy, correct, but inefficient.
Functional Streaming: Ideas:Push
❖ Push
❖ step 0: provide function, which our stream will call and run for
starting data flow process.
❖ step 1: provide ‘back’ callback for flow control.
❖ step 2: hide complexity by providing set of built-in combinators
❖ step 4: create data flow DSL on top of this.
❖ step 5: decouple generation of running functions from DSL
❖ representation (materialize), Akka.
Functional Streaming: Ideas:Push
❖ Push
❖ step 0: provide function, which our stream will call
❖ step 1: provide ‘back’ callback for flow control.
❖ ste
❖ p 2: hide complexity by providing set of built-in
combinators
❖ step 4: create data flow DSL on top of this.
trait PushStream0[T]
{
def subscribe(
onNext: T => Unit,
onEnd: Unit => Unit,
onError: Unit => Unit,
): PushSubscription0
}
Functional Streaming: Ideas:Push
❖ Push
❖ step 1: provide ‘back’ callback for flow control.
❖ ste
❖ p 2: hide complexity by providing set of built-in co
❖ mbinators
❖ step 4: create data flow DSL on top of this.
trait PushStream1[T]
{
def subscribe(
onNext: (T, OutHandler) => Unit,
onEnd: OutHandler => Unit,
onError: OutHandler => Unit,
): PushSubscription1
}
trait OutHandler
{
def onPull()
def onFinish()
Functional Streaming: Ideas:Push
❖ Push
❖ step 2: hide complexity by providing set of built-in
combinators
❖ step 4: create data flow DSL on top of this.
val process = stream.map(_.aXribute(model))
.lter(_.p > limit)
.truffle(3000, 1 second)(_.dropLast).
. aggregate(average)
.saveToDb(ctx)
process.run()
// Rx —- near 80 combinators
// akka-streams —- near ???
Functional Streaming: Ideas:Push
❖ Push
❖ step 4: [akka] create data flow DSL.
❖
advInput ~> aXribute ~>
lterByLocation ~> retrieweProle ~> advert
locationInput ~> lterByLocation
Functional streaming: Active channel
Write callback
// if writer exists
Read callback
//if reader exists
Corner cases:
- Unbuffered channel
- Unlimited buffer
scala-gopher
❖ Akka extension + Macros on top of SIP22-async
❖ Integrate CSP Algebra and scala concurrency primitives
❖ Provides:
❖ asynchronous API inside general control-flow
❖ pseudo-synchronous API inside go{ .. } or async{ ..}
blocks
❖ Techreport: goo.gl/dbT3P7
def nPrimes(n:Int):Future[List[Int]]= {
val in = makeChannel[Int]()
val out = makeChannel[Int]()
go {
for(i <- 1 to Int.MaxValue) in.write(i)
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
go {
for(i <- 1 to n) yield out.read
}
}
def nPrimes(n:Int):Future[List[Int]]= {
val in = makeChannel[Int]()
val out = makeChannel[Int]()
go {
for(i <- 1 to n*n) out.write(i)
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
go {
for(i <- 1 to n) yield out.read
}
}
go {
for(i <- 1 to Int.MaxValue)
in.write(i)
}
def nPrimes(n:Int):Future[List[Int]]= {
val in = makeChannel[Int]()
val out = makeChannel[Int]()
go {
for(i <- 1 to Int.MaxValue) in.write(i)
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
go {
for(i <- 1 to n) yield out.read
}
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
def nPrimes(n:Int):Future[List[Int]]= {
val in = makeChannel[Int]()
val out = makeChannel[Int]()
go {
for(i <- 1 to Int.MaxValue) in.write(i)
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
go {
for(i <- 1 to n) yield out.read
}
}
go {
for(i <- 1 to n) yield out.read
}
def nPrimes(n:Int):Future[List[Int]]= {
val in = makeChannel[Int]()
val out = makeChannel[Int]()
go {
for(i <- 1 to Int.MaxValue) in.write(i)
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
go {
for(i <- 1 to n) yield out.read
}
}
Goroutines
❖ go[X](body: X):Future[X]
❖ Wrapper around async +
❖ translation of high-order functions into async form
❖ handling of defer statement
go {
(1 to n).map(i => out.read)
}
- async: translate ‘pseudo-synchonic’ code into asynchronous non-blocking form.
- go: translate invocation of synchronic hight-order functions into asynchronous one
val sum(a:Future[Int],b:Future[Int]):Future[Int]=
async{
await(a) + await(b)
}
// SIP 22
// have stable implementation, but not finished yet.
val sum(a:Future[Int],b:Future[Int]):Future[Int]=
{
var sm = new class StateMachine122 {
var (fa,ra,fb,rb,r,s) = (a,Int(),b,Int(),0)
def apply():Future[Unit] =
s.state match {
case 0 => fa.map{ x => a=x; s = 1; apply() }
case 1 => fb.map{ x => b=x; s = 2; apply() }
case 2 => r = ra + rb
}
}. apply() map (_ => sm.r)
}
go {
(1 to n).map(i => out.read)
}
- async: translate ‘pseudo-synchonic’ code into asynchronous non-blocking form.
- go: translate invocation of synchronic hight-order functions into asynchronous one
val sum(a:Future[Int],b:Future[Int]):Future[Int]=
async{
await(a) + await(b)
}
// SIP 22
// have stable implementation, but not finished yet.
// want asynchronous read inside map
// Can’t work with expressions inside hight-order functions, like map
Goroutines
❖ translation of hight-order functions into async form
❖ f(g): f: (A=>B)=>C in g: A=>B,
❖ g is invocation-only in f iff
❖ g called in f or in some h inside f : g invocation-only in h
❖ g is
❖ not stored in memory behind f
❖ not returned from f as return value
❖ Collection API high-order methods are invocation-only
Translation of invocation-only functions
❖ f: ((A=>B)=>C), g: (A=>B), g invocation-only in f
❖ f’: ((A=>Future[B])=>Future[C]) g’: (A=>Future[B])
❖ await(g’) == g => await(f’) == f
❖ f’ => await[translate(f)]
❖ g(x) => await(g’(x))
❖ h(g) => await(h’(g’)) iff g is invocation-only in h
❖ That’s all
❖ (implemented for specific shapes and parts of scala collection
API)
def nPrimes(n:Int):Future[List[Int]]= {
val in = makeChannel[Int]()
val out = makeChannel[Int]()
go {
for(i <- 1 to n*n) in.write(i)
}
go {
select.fold(in){ (ch,s) =>
s match {
case p:ch.read => out.write(p)
ch.filter(_ % p != 0)
}
}
}
go {
for(i <- 1 to n) yield out.read
}
}
go {
for(i <- 1 to n) yield out.read
}
go {
(1 to n).map(i => out.read)
}
async{
await(t[(1 to n).map(i => out.read)])
}
async{
await((1 to n).mapAsync(t[i => async(out.read)]))
}
async{
await((1 to n).mapAsync(i => async(await(out.aread)))
}
(1 to n).mapAsync(i => out.aread)
Channels
❖ Channel[A] <: Input[A] + Output[A]
❖ Unbuffered
❖ Buffered
❖ Dynamically growing buffers [a-la actor mailbox]
❖ One-time channels [Underlaying promise/Future]
❖ Custom
CSP
Input[A] - internal API
trait Input[A]
{
type read = A
def cbread(f: ContRead[A,B]=>Option[
ContRead.In[A] => Future[Continuated[B]])
…..
}
case class ContRead[A,B](
function: F,
channel: Channel[A],
flowTermination: FlowTermination[B]
)
// in ConRead companion object
sealed trait In[+A]
case class Value(a:A) extends In[A]
case class Failure(ex: Throwable] extends In[Nothing]
case object Skip extends In[Nothing]
case object ChannelClosed extends In[Nothing]
ContRead[A,B].F
Continuated[B]
• ContRead
• ContWrite
• Skip
• Done
• Never
Input[A] - external API
trait Input[A]
{
……
def aread: Future[A] = <implementation…>
def read: A = macro <implementation … >
….
def map[B](f: A=>B): Input[B] = ….
// or, zip, filter, … etc
await(aread)
+ usual operations on streams in functional language
Output[A] - API
trait Output[A]
{
type write = A
def cbwrite(f: ContWrite[A,B]=>Option[
(A,Future[Continuated[B]])],
ft: FlowTermination[B])
…..
def awrite(a:A): Future[A] = ….
def write(a:A): A = …. << await(awrite)
….
ContWrite[A,B].F
case class ContWrite[A,B](
function: F,
channel: Channel[A],
flowTermination: FlowTermination[B]
)
Selector ss
go {
for{
select{
case c1 -> x : … // P
case c2 <- y : … // Q
}
}
Go language:
go {
select.forever {
case x : c1.read => … // P
case y : c2.write => … // Q
}
}
Scala:
Provide set of flow combinators:
forever, once, fold
select.aforever {
case x : c1.read => … // P
case y : c2.write => … // Q
}
select: fold API
def bonacci(c: Output[Long], quit: Input[Boolean]): Future[(Long,Long)] =
select.afold((0L,1L)) { case ((x,y),s) =>
s match {
case x: c.write => (y, x+y)
case q: quit.read =>
select.exit((x,y))
}
}
fold/afold:
• special syntax for tuple support
• ’s’: selector pseudoobject
• s match must be the first statement
• select.exit((..)) to return value from flow
Transputer
❖ Actor-like object with set of input/output ports, which
can be connected by channels
❖ Participate in actor systems supervisors hierarchy
❖ SelectStatement
❖ A+B (parallel execution, common restart)
❖ replicate
Transputer: select
class Zipper[T] extends SelectTransputer
{
val inX: InPort[T]
val inY: InPort[T]
val out: OutPort[(T,T)]
loop {
case x: inX.read => val y = inY.read
out write (x,y)
case y: inY.read => val x = inX.read
out.write((x,y))
}
}
inX
inY
out
Transputer: replicate
val r = gopherApi.replicate[SMTTransputer](10)
( r.dataInput.distribute( (_.hashCode % 10 ) ).
.controlInput.duplicate().
out.share()
)
dataInput
controlInput
share
Programming techniques
❖ Dynamic recursive dataflow schemas
❖ configuration in state
❖ Channel-based two-wave generic API
❖ expect channels for reply
Dynamic recursive dataflow
select.fold(output){ (out, s) => s match {
case x:input.read => select.once {
case x:out.write =>
case select.timeout => control.distributeBandwidth match {
case Some(newOut) => newOut.write(x)
out | newOut
case None => control.report("Can't increase bandwidth")
out
}
}
case select.timeout => out match {
case OrOutput(frs,snd) => snd.close
frs
case _ => out
}
}
dynamically increase and decrease bandwidth in dependency from load
Dynamic recursive dataflow
select.fold(output){ (out, s) => s match {
case x:input.read => select.once {
case x:out.write =>
case select.timeout => control.distributeBandwidth match {
case Some(newOut) => newOut.write(x)
out | newOut
case None => control.report("Can't increase bandwidth")
out
}
}
case select.timeout => out match {
case OrOutput(frs,snd) => snd.close
frs
case _ => out
}
}
dynamically increase and decrease bandwidth in dependency from load
case select.timeout =>
control.distributeBandwidth match {
case Some(newOut) => newOut.write(x)
out | newOut
case None =>
control.report("Can't increase bandwidth")
out
Dynamic recursive dataflow
select.fold(output){ (out, s) => s match {
case x:input.read => select.once {
case x:out.write =>
case select.timeout => control.distributeBandwidth match {
case Some(newOut) => newOut.write(x)
out | newOut
case None => control.report("Can't increase bandwidth")
out
}
}
case select.timeout => out match {
case OrOutput(frs,snd) => snd.close
frs
case _ => out
}
}
dynamically increase and decrease bandwidth in dependency from load
case select.timeout => out match {
case OrOutput(frs,snd) => snd.close
frs
case _ => out
}
Channel-based generic API
❖ Endpoint instead function call
❖ f: A=>B; af: A => Future[B]
❖ endpoint: Channel[A,Channel[B]]
❖ Recursive
❖ case class M(A,Channel[M])
❖ f: (A,M) => M (dataflow configured by input)
Channel-based generic API
trait Broadcast[T]
{
val listeners: Output[Channel[T]]
val messages: Output[T]
def send(v:T):Unit = { messages.write(v) }
….
• message will received by all listeners
Channel-based generic API
class BroadcastImpl[T]
{
val listeners: Channel[Channel[T]]
val messages: Channel[T] = makeChannel[Channel[T]]
def send(v:T):Unit = { messages.write(v) }
….
}
// private part
case class Message(next:Channel[Message],value:T)
select.afold(makeChannel[Message]) { (bus, s) =>
s match {
case v: messages.read => val newBus = makeChannel[Message]
current.write(Message(newBus,v))
newBus
case ch: listeners.read => select.afold(bus) { (current,s) =>
s match {
case msg:current.read => ch.awrite(msg.value)
current.write(msg)
msg.next
}
}
current
Channel-based generic API
val listeners: Channel[Channel[T]]
val messages: Channel[T] = makeChannel[]
// private part
case class Message(next:Channel[Message],value:T)
select.afold(makeChannel[Message]) { (bus, s) =>
s match {
case v: message.read => val newBus = makeChannel[Message]
current.write(Message(newBus,v))
newBus
case ch: listener.read => select.afold(bus) { (current,s) =>
s match {
case msg:current.read => ch.awrite(msg.value)
current.write(msg)
msg.next
}
}
• state - channel [bus], for which all listeners are subscribed
• on new message - send one to bus with pointer to the next bus state
• listener on new message in bus - handle, change current and send again
• on new listener - propagate
Channel-based generic API
val listener: Channel[Channel[T]]
val message: Channel[T] = makeChannel[]
// private part
case class Message(next:Channel[Message],value:T)
select.afold(makeChannel[Message]) { (bus, s) =>
s match {
case v: message.read => val newBus = makeChannel[Message]
current.write(Message(newBus,v))
newBus
case ch: listener.read => select.afold(bus) { (current,s) =>
s match {
case msg:current.read => ch.awrite(msg.value)
msg.next
}
}
current
• state - channel [bus], for which all listeners are subscribed
• on new message - send one to bus with pointer to the next bus state
• listener on new message in bus - handle, change current and send again
• on new listener - propagate
s match {
case msg:current.read => ch.awrite(msg.value)
current.write(msg)
msg.next
}
Channel-based generic API
val listener: Channel[Channel[T]]
val message: Channel[T] = makeChannel[]
// private part
case class Message(next:Channel[Message],value:T)
select.afold(makeChannel[Message]) { (bus, s) =>
s match {
case v: message.read => val newBus = makeChannel[Message]
current.write(Message(newBus,v))
newBus
case ch: listener.read => select.afold(bus) { (current,s) =>
s match {
case msg:current.read => ch.awrite(msg.value)
current.write(msg)
msg.next
}
}
current
• state - channel [bus], for which all listeners are subscribed
• on new message - send one to bus with pointer to the next bus state
• listener on new message in bus - handle, change current and send again
•
val newBus = makeChannel[Message]
current.write(Message(newBus,v))
newBus
Adoption: first lessons.
❖ Fluent inline API vs OO
❖ select folds are more popular than creating
transputer classes.
❖ In-place handling for
❖ end of streams.
❖ errors.
error handling inside select
val f = select.afold(s0) { (x, s) =>
s match {
case v: channel.read => doSomeProcessing(x,v)
case v: channel.done => doCleanup(x)
select.exit(x)
case ex: select.error => if (canContinue(ex)) {
logError(ex)
x
} else throw ex
case t: select.timeout => doSomethingWithTimeout() ..
}
// vs recreation of fold in future
Scala concurrency libraries
Flexibility
Scalability
Level
Actors
• Actors
• low level,
• great flexibility and scalability
• Akka-Streams
• low flexibility
• hight-level, scalable
• SCO
• low scalability
• hight-level, flexible
• Reactive Isolated
• hight-level, scalable,
• allows delegation
• Gopher
• can emulate each style
Streams
SCO
Subscript
Language
Scala-Gopher: Conclusion
❖ Native integration of CSP into Scala is possible
❖ have a place in a Scala concurrency model zoo
❖ Bring well-established techniques to Scala world
❖ (recursive dataflow schemas; channel API)
❖ Translation of invocation-only high-order functions into
async form can be generally recommended.
❖ (with TASTY transformation inside libraries can be done
automatically)
Thanks for attention
❖ Questions ?
❖ https://github.com/rssh/scala-gopher
❖ ruslan shevchenko: ruslan@shevchenko.kiev.ua

More Related Content

What's hot

Getting Started with Raspberry Pi - DCC 2013.1
Getting Started with Raspberry Pi - DCC 2013.1Getting Started with Raspberry Pi - DCC 2013.1
Getting Started with Raspberry Pi - DCC 2013.1Tom Paulus
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Leonardo Borges
 
Explaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to ComeExplaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to ComeCory Forsyth
 
ES6 - Next Generation Javascript
ES6 - Next Generation JavascriptES6 - Next Generation Javascript
ES6 - Next Generation JavascriptRamesh Nair
 
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...John De Goes
 
EcmaScript 6 - The future is here
EcmaScript 6 - The future is hereEcmaScript 6 - The future is here
EcmaScript 6 - The future is hereSebastiano Armeli
 
Halogen: Past, Present, and Future
Halogen: Past, Present, and FutureHalogen: Past, Present, and Future
Halogen: Past, Present, and FutureJohn De Goes
 
Intro to Functional Programming in Scala
Intro to Functional Programming in ScalaIntro to Functional Programming in Scala
Intro to Functional Programming in ScalaShai Yallin
 
Stream or not to Stream?

Stream or not to Stream?
Stream or not to Stream?

Stream or not to Stream?
Lukasz Byczynski
 
The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final TaglessJohn De Goes
 
The Joy of Server Side Swift Development
The Joy  of Server Side Swift DevelopmentThe Joy  of Server Side Swift Development
The Joy of Server Side Swift DevelopmentGiordano Scalzo
 
MTL Versus Free
MTL Versus FreeMTL Versus Free
MTL Versus FreeJohn De Goes
 
Kotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime PerformanceKotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime Performanceintelliyole
 
Functor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadFunctor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadOliver Daff
 
Intro to Pig UDF
Intro to Pig UDFIntro to Pig UDF
Intro to Pig UDFChris Wilkes
 
JavaScript Event Loop
JavaScript Event LoopJavaScript Event Loop
JavaScript Event LoopDesignveloper
 
Apache PIG - User Defined Functions
Apache PIG - User Defined FunctionsApache PIG - User Defined Functions
Apache PIG - User Defined FunctionsChristoph Bauer
 
All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!John De Goes
 

What's hot (19)

Getting Started with Raspberry Pi - DCC 2013.1
Getting Started with Raspberry Pi - DCC 2013.1Getting Started with Raspberry Pi - DCC 2013.1
Getting Started with Raspberry Pi - DCC 2013.1
 
Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012Continuation Passing Style and Macros in Clojure - Jan 2012
Continuation Passing Style and Macros in Clojure - Jan 2012
 
The best language in the world
The best language in the worldThe best language in the world
The best language in the world
 
Explaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to ComeExplaining ES6: JavaScript History and What is to Come
Explaining ES6: JavaScript History and What is to Come
 
ES6 - Next Generation Javascript
ES6 - Next Generation JavascriptES6 - Next Generation Javascript
ES6 - Next Generation Javascript
 
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...
The Easy-Peasy-Lemon-Squeezy, Statically-Typed, Purely Functional Programming...
 
EcmaScript 6 - The future is here
EcmaScript 6 - The future is hereEcmaScript 6 - The future is here
EcmaScript 6 - The future is here
 
Halogen: Past, Present, and Future
Halogen: Past, Present, and FutureHalogen: Past, Present, and Future
Halogen: Past, Present, and Future
 
Intro to Functional Programming in Scala
Intro to Functional Programming in ScalaIntro to Functional Programming in Scala
Intro to Functional Programming in Scala
 
Stream or not to Stream?

Stream or not to Stream?
Stream or not to Stream?

Stream or not to Stream?

 
The Death of Final Tagless
The Death of Final TaglessThe Death of Final Tagless
The Death of Final Tagless
 
The Joy of Server Side Swift Development
The Joy  of Server Side Swift DevelopmentThe Joy  of Server Side Swift Development
The Joy of Server Side Swift Development
 
MTL Versus Free
MTL Versus FreeMTL Versus Free
MTL Versus Free
 
Kotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime PerformanceKotlin Bytecode Generation and Runtime Performance
Kotlin Bytecode Generation and Runtime Performance
 
Functor, Apply, Applicative And Monad
Functor, Apply, Applicative And MonadFunctor, Apply, Applicative And Monad
Functor, Apply, Applicative And Monad
 
Intro to Pig UDF
Intro to Pig UDFIntro to Pig UDF
Intro to Pig UDF
 
JavaScript Event Loop
JavaScript Event LoopJavaScript Event Loop
JavaScript Event Loop
 
Apache PIG - User Defined Functions
Apache PIG - User Defined FunctionsApache PIG - User Defined Functions
Apache PIG - User Defined Functions
 
All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!All Aboard The Scala-to-PureScript Express!
All Aboard The Scala-to-PureScript Express!
 

Similar to N flavors of streaming

Csp scala wixmeetup2016
Csp scala wixmeetup2016Csp scala wixmeetup2016
Csp scala wixmeetup2016Ruslan Shevchenko
 
Programming Languages: some news for the last N years
Programming Languages: some news for the last N yearsProgramming Languages: some news for the last N years
Programming Languages: some news for the last N yearsRuslan Shevchenko
 
Java/Scala Lab: Руслан Шевченко - Implementation of CSP (Communication Sequen...
Java/Scala Lab: Руслан Шевченко - Implementation of CSP (Communication Sequen...Java/Scala Lab: Руслан Шевченко - Implementation of CSP (Communication Sequen...
Java/Scala Lab: Руслан Шевченко - Implementation of CSP (Communication Sequen...GeeksLab Odessa
 
scala-gopher: async implementation of CSP for scala
scala-gopher:  async implementation of CSP  for  scalascala-gopher:  async implementation of CSP  for  scala
scala-gopher: async implementation of CSP for scalaRuslan Shevchenko
 
Emerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the HorizonEmerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the HorizonAlex Payne
 
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...GeeksLab Odessa
 
23_Advanced_Processors controller system
23_Advanced_Processors controller system23_Advanced_Processors controller system
23_Advanced_Processors controller systemstellan7
 
Meet Up - Spark Stream Processing + Kafka
Meet Up - Spark Stream Processing + KafkaMeet Up - Spark Stream Processing + Kafka
Meet Up - Spark Stream Processing + KafkaKnoldus Inc.
 
Artimon - Apache Flume (incubating) NYC Meetup 20111108
Artimon - Apache Flume (incubating) NYC Meetup 20111108Artimon - Apache Flume (incubating) NYC Meetup 20111108
Artimon - Apache Flume (incubating) NYC Meetup 20111108Mathias Herberts
 
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.Ruslan Shevchenko
 
Big Data LDN 2017: Processing Fast Data With Apache Spark: the Tale of Two APIs
Big Data LDN 2017: Processing Fast Data With Apache Spark: the Tale of Two APIsBig Data LDN 2017: Processing Fast Data With Apache Spark: the Tale of Two APIs
Big Data LDN 2017: Processing Fast Data With Apache Spark: the Tale of Two APIsMatt Stubbs
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
So you think you can stream.pptx
So you think you can stream.pptxSo you think you can stream.pptx
So you think you can stream.pptxPrakash Chockalingam
 
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data EcosystemWprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data EcosystemSages
 
Flux and InfluxDB 2.0 by Paul Dix
Flux and InfluxDB 2.0 by Paul DixFlux and InfluxDB 2.0 by Paul Dix
Flux and InfluxDB 2.0 by Paul DixInfluxData
 
Natural Language Processing with CNTK and Apache Spark with Ali Zaidi
Natural Language Processing with CNTK and Apache Spark with Ali ZaidiNatural Language Processing with CNTK and Apache Spark with Ali Zaidi
Natural Language Processing with CNTK and Apache Spark with Ali ZaidiDatabricks
 
Pune Clojure Course Outline
Pune Clojure Course OutlinePune Clojure Course Outline
Pune Clojure Course OutlineBaishampayan Ghose
 
Deep Learning and TensorFlow
Deep Learning and TensorFlowDeep Learning and TensorFlow
Deep Learning and TensorFlowOswald Campesato
 

Similar to N flavors of streaming (20)

Csp scala wixmeetup2016
Csp scala wixmeetup2016Csp scala wixmeetup2016
Csp scala wixmeetup2016
 
Programming Languages: some news for the last N years
Programming Languages: some news for the last N yearsProgramming Languages: some news for the last N years
Programming Languages: some news for the last N years
 
Java/Scala Lab: Руслан Шевченко - Implementation of CSP (Communication Sequen...
Java/Scala Lab: Руслан Шевченко - Implementation of CSP (Communication Sequen...Java/Scala Lab: Руслан Шевченко - Implementation of CSP (Communication Sequen...
Java/Scala Lab: Руслан Шевченко - Implementation of CSP (Communication Sequen...
 
scala-gopher: async implementation of CSP for scala
scala-gopher:  async implementation of CSP  for  scalascala-gopher:  async implementation of CSP  for  scala
scala-gopher: async implementation of CSP for scala
 
Emerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the HorizonEmerging Languages: A Tour of the Horizon
Emerging Languages: A Tour of the Horizon
 
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
Java/Scala Lab: Анатолий Кметюк - Scala SubScript: Алгебра для реактивного пр...
 
Venkat ns2
Venkat ns2Venkat ns2
Venkat ns2
 
23_Advanced_Processors controller system
23_Advanced_Processors controller system23_Advanced_Processors controller system
23_Advanced_Processors controller system
 
Meet Up - Spark Stream Processing + Kafka
Meet Up - Spark Stream Processing + KafkaMeet Up - Spark Stream Processing + Kafka
Meet Up - Spark Stream Processing + Kafka
 
Artimon - Apache Flume (incubating) NYC Meetup 20111108
Artimon - Apache Flume (incubating) NYC Meetup 20111108Artimon - Apache Flume (incubating) NYC Meetup 20111108
Artimon - Apache Flume (incubating) NYC Meetup 20111108
 
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
Scala-Gopher: CSP-style programming techniques with idiomatic Scala.
 
Ns network simulator
Ns network simulatorNs network simulator
Ns network simulator
 
Big Data LDN 2017: Processing Fast Data With Apache Spark: the Tale of Two APIs
Big Data LDN 2017: Processing Fast Data With Apache Spark: the Tale of Two APIsBig Data LDN 2017: Processing Fast Data With Apache Spark: the Tale of Two APIs
Big Data LDN 2017: Processing Fast Data With Apache Spark: the Tale of Two APIs
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
So you think you can stream.pptx
So you think you can stream.pptxSo you think you can stream.pptx
So you think you can stream.pptx
 
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data EcosystemWprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
 
Flux and InfluxDB 2.0 by Paul Dix
Flux and InfluxDB 2.0 by Paul DixFlux and InfluxDB 2.0 by Paul Dix
Flux and InfluxDB 2.0 by Paul Dix
 
Natural Language Processing with CNTK and Apache Spark with Ali Zaidi
Natural Language Processing with CNTK and Apache Spark with Ali ZaidiNatural Language Processing with CNTK and Apache Spark with Ali Zaidi
Natural Language Processing with CNTK and Apache Spark with Ali Zaidi
 
Pune Clojure Course Outline
Pune Clojure Course OutlinePune Clojure Course Outline
Pune Clojure Course Outline
 
Deep Learning and TensorFlow
Deep Learning and TensorFlowDeep Learning and TensorFlow
Deep Learning and TensorFlow
 

More from Ruslan Shevchenko

Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]Ruslan Shevchenko
 
Svitla talks 2021_03_25
Svitla talks 2021_03_25Svitla talks 2021_03_25
Svitla talks 2021_03_25Ruslan Shevchenko
 
Papers We Love / Kyiv : PAXOS (and little about other consensuses )
Papers We Love / Kyiv :  PAXOS (and little about other consensuses )Papers We Love / Kyiv :  PAXOS (and little about other consensuses )
Papers We Love / Kyiv : PAXOS (and little about other consensuses )Ruslan Shevchenko
 
Scala / Technology evolution
Scala  / Technology evolutionScala  / Technology evolution
Scala / Technology evolutionRuslan Shevchenko
 
{co/contr} variance from LSP
{co/contr} variance  from LSP{co/contr} variance  from LSP
{co/contr} variance from LSPRuslan Shevchenko
 
SE 20016 - programming languages landscape.
SE 20016 - programming languages landscape.SE 20016 - programming languages landscape.
SE 20016 - programming languages landscape.Ruslan Shevchenko
 
Few simple-type-tricks in scala
Few simple-type-tricks in scalaFew simple-type-tricks in scala
Few simple-type-tricks in scalaRuslan Shevchenko
 
Why scala is not my ideal language and what I can do with this
Why scala is not my ideal language and what I can do with thisWhy scala is not my ideal language and what I can do with this
Why scala is not my ideal language and what I can do with thisRuslan Shevchenko
 
Scala jargon cheatsheet
Scala jargon cheatsheetScala jargon cheatsheet
Scala jargon cheatsheetRuslan Shevchenko
 
Java & low latency applications
Java & low latency applicationsJava & low latency applications
Java & low latency applicationsRuslan Shevchenko
 
R ext world/ useR! Kiev
R ext world/ useR!  KievR ext world/ useR!  Kiev
R ext world/ useR! KievRuslan Shevchenko
 
Jslab rssh: JS as language platform
Jslab rssh:  JS as language platformJslab rssh:  JS as language platform
Jslab rssh: JS as language platformRuslan Shevchenko
 
Behind OOD: domain modelling in post-OO world.
Behind OOD:  domain modelling in post-OO world.Behind OOD:  domain modelling in post-OO world.
Behind OOD: domain modelling in post-OO world.Ruslan Shevchenko
 
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
JDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation streamJDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation stream
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation streamRuslan Shevchenko
 
Ruslan.shevchenko: most functional-day-kiev 2014
Ruslan.shevchenko: most functional-day-kiev 2014Ruslan.shevchenko: most functional-day-kiev 2014
Ruslan.shevchenko: most functional-day-kiev 2014Ruslan Shevchenko
 
Web architecture - overview of techniques.
Web architecture - overview of  techniques.Web architecture - overview of  techniques.
Web architecture - overview of techniques.Ruslan Shevchenko
 
Javascript in modern scala backend. [russian]
Javascript in modern scala backend.  [russian]  Javascript in modern scala backend.  [russian]
Javascript in modern scala backend. [russian] Ruslan Shevchenko
 

More from Ruslan Shevchenko (20)

Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]Embedding Generic Monadic Transformer into Scala. [Tfp2022]
Embedding Generic Monadic Transformer into Scala. [Tfp2022]
 
Svitla talks 2021_03_25
Svitla talks 2021_03_25Svitla talks 2021_03_25
Svitla talks 2021_03_25
 
Akka / Lts behavior
Akka / Lts behaviorAkka / Lts behavior
Akka / Lts behavior
 
Papers We Love / Kyiv : PAXOS (and little about other consensuses )
Papers We Love / Kyiv :  PAXOS (and little about other consensuses )Papers We Love / Kyiv :  PAXOS (and little about other consensuses )
Papers We Love / Kyiv : PAXOS (and little about other consensuses )
 
Scala / Technology evolution
Scala  / Technology evolutionScala  / Technology evolution
Scala / Technology evolution
 
{co/contr} variance from LSP
{co/contr} variance  from LSP{co/contr} variance  from LSP
{co/contr} variance from LSP
 
SE 20016 - programming languages landscape.
SE 20016 - programming languages landscape.SE 20016 - programming languages landscape.
SE 20016 - programming languages landscape.
 
Few simple-type-tricks in scala
Few simple-type-tricks in scalaFew simple-type-tricks in scala
Few simple-type-tricks in scala
 
Why scala is not my ideal language and what I can do with this
Why scala is not my ideal language and what I can do with thisWhy scala is not my ideal language and what I can do with this
Why scala is not my ideal language and what I can do with this
 
Scala jargon cheatsheet
Scala jargon cheatsheetScala jargon cheatsheet
Scala jargon cheatsheet
 
Java & low latency applications
Java & low latency applicationsJava & low latency applications
Java & low latency applications
 
IDLs
IDLsIDLs
IDLs
 
R ext world/ useR! Kiev
R ext world/ useR!  KievR ext world/ useR!  Kiev
R ext world/ useR! Kiev
 
Jslab rssh: JS as language platform
Jslab rssh:  JS as language platformJslab rssh:  JS as language platform
Jslab rssh: JS as language platform
 
Behind OOD: domain modelling in post-OO world.
Behind OOD:  domain modelling in post-OO world.Behind OOD:  domain modelling in post-OO world.
Behind OOD: domain modelling in post-OO world.
 
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
JDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation streamJDays Lviv 2014:  Java8 vs Scala:  Difference points & innovation stream
JDays Lviv 2014: Java8 vs Scala: Difference points & innovation stream
 
Ruslan.shevchenko: most functional-day-kiev 2014
Ruslan.shevchenko: most functional-day-kiev 2014Ruslan.shevchenko: most functional-day-kiev 2014
Ruslan.shevchenko: most functional-day-kiev 2014
 
Web architecture - overview of techniques.
Web architecture - overview of  techniques.Web architecture - overview of  techniques.
Web architecture - overview of techniques.
 
R scala 17_05_2014
R scala 17_05_2014R scala 17_05_2014
R scala 17_05_2014
 
Javascript in modern scala backend. [russian]
Javascript in modern scala backend.  [russian]  Javascript in modern scala backend.  [russian]
Javascript in modern scala backend. [russian]
 

Recently uploaded

Clustering techniques data mining book ....
Clustering techniques data mining book ....Clustering techniques data mining book ....
Clustering techniques data mining book ....ShaimaaMohamedGalal
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto GonzĂĄlez Trastoy
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendArshad QA
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 

Recently uploaded (20)

Clustering techniques data mining book ....
Clustering techniques data mining book ....Clustering techniques data mining book ....
Clustering techniques data mining book ....
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and Backend
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 

N flavors of streaming

  • 1. N FLAVORS OF STREAMING // Current landscape & ideas Ruslan Shevchenko <ruslan@shevchenko.kiev.ua> https://github.com/rssh @rssh1
  • 2. N FLAWORS OF STREAMING - main ideas // from board-based micro-optimizations to distributed computing - most notable implementations - programming languages - Sisal //Streaming, DEC, Occam //CSP origin, INMOS Limbo Go //Unix/Plan9 Inferno Traditions, ,Elm //FRP generalization ,Orc //channel-based , etc… - scala implementations (iteratee/enumeratee, scalaz-streams,fs2, akka-streams, gopher, monix.io, etc ….) - scala-gopher: state and news.
  • 3. - Timed stream of data [or stream processor] as language entity - Combinators - Data flow, orthogonal to Control flow When person device is tracked in retail store, sometimes, send him message from pizzeria with discount on his/she favorite food. When connect to wifi show personalized advertising // Q: why ? - let’s model
  • 4. STREAMING : WHERE IS GAIN ? locationRequests.foreach{ r => ctx.saveRequest(r) for{deviceId <- ctx.retrieveDeviceId(r) profile <- ctx.findProfile(deviceId) if (profile.eligibleToSend) message <- prepareMessage(profile) } { ctx.send(message) cts.saveAction(profileData.id,message,now) } } // traditional approach (pseudocode)
  • 5. STREAMING : WHERE IS GAIN ? locationRequests.foreach{ r => ctx.saveRequest(r) for{deviceId <- ctx.retrieveDeviceId(r) profile <- ctx.findProfile(deviceId) if (profile.eligibleToSend) message <- prepareMessage(profile) } { ctx.send(message) cts.saveAction(profileData.id,message,now) } } // traditional approach (pseudocode) val graph = locationTracking.tee(db.save).amap( ctx.retrieveDevice ). amap( ctx.findProfille ). filter{ _.eligibleToSend }. amap(prepareMessage). tee(ctx.send).sink(ctx.saveAction) graph.run() // streaming approach (pseudocode)
  • 6. MORE COMPLEX EXAMPLE - SHOW ADS ON REQUEST When person device is tracked in retail store, Then when h/she connect to wifi show personalized advertising
  • 7. SHOW ADS ON REQUEST // traditional approach (pseudocode) locationTracking.foreach(r => for(deviceId <- ctx.retrieveDevice) db.save(deviceId, r.placement) ) adRequest.foreach( r -> for( device <- ctx.retrieveDevice placement <- db.retrievePlacements(device, 10 min) profile <- findProfile(deviceId) if (profile.eligibleToAd) advertising <- createAdvertising(profile) ) yield advertising )
  • 8. WE NEED STATE // traditional approach (pseudocode) locationTracking.foreach(r => for(deviceId <- ctx.retrieveDevice) db.save(deviceId, r.placement) ) adRequest.foreach( r -> for( device <- ctx.retrieveDevice placement <- db.retrievePlacements(device, 10 min) profile <- findProfile(deviceId) if (profile.eligibleToAd) advertising <- createAdvertising(profile) ) yield advertising )
  • 9. NO EXPLICIT STATE // traditional approach (pseudocode) locationTracking.foreach(r => for(deviceId <- ctx.retrieveDevice) db.save(deviceId, r.placement) ) adRequest.foreach( r -> for( device <- ctx.retrieveDevice placement <- db.retrievePlacements(device, 10 min) profile <- findProfile(deviceId) if (profile.eligibleToAd) advertising <- createAdvertising(profile) ) yield advertising ) STATE val deviceLocations = locationTracking.retrieveDevice val ads = adRequests.amap(retrieveDevice) .crossBy(deviceLocations, 10 min)(_.placement) .amap(findProfile(deviceId)filter(_.eligibleToAd) amap(ctx.createAdvertising) graph(deviceLocations,ads).run (state is an implementation detail of deviceLocations stream. [crossBy ]
  • 10. STREAM-BASED API: • Hight level • Save thinking about state • Incapsulate effects into stream F:A=>B S MAM F: S[A] => S[B] • Persistent • Distributed • Monitored ……. • Deferred…
  • 11. HISTORY SISAL: 1983 (Michigan University) - imperative function language; implicit parallelism type ints = stream[integer] function Filter(S: ints, M: Integer return Ints) for I in S return stream of I unless mod(i,m)=0 end for end function function Integers (return Ints) for initial I:=3 while true repeat I:= old I + 2 return stream of I end for function PrimesUpTo(Limit: Integer return Ints) let maxs := integer(sqrt(real(Liimit)) in for initial D:=Integer(), t:=2 while T < Limit repeat T := first(old S) S: = if T < S Filter(rest(old S), T) Else rest(old S) endif return stream of T end for end let end function
  • 12. HISTORY: SISAL SISAL: 1983 (Michigan University) - implicit parallelism, - imperative function language - outperform Fortran in some cases - direct descendant in today-s language: CUDA kernel functions in Nvidia GPU __global__ void vecAdd(double *a, double *b, double *c, int n) { int id = blockIdx.x*blockDim.x+threadIdx.x; // Make sure we do not go out of bounds if (id < n) c[id] = a[id] + b[id]; } vecAdd<<<dimGrid, dimBlock>>>(ad, bd);
  • 13. HISTORY: CSP ❖ 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, )
  • 14. 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) History: Occam
  • 15. ❖ 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 Arduino. History: Occam
  • 16. History: 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 Forward David Leo Presotto Rob Pike Dennis M. Ritchie Ken Thompson
  • 17. 13. Go: simple code example func bonacci(c chan int, quit chan bool) { go { x, y := 0, 1 for (){ select { case c <- x : x, y = y, x+y case q<- quit: break; } } close(c) } } c = make(chan int); quit= make(chan bool); bonacci(c,quit) for i := range c { fmt.Println(i) if (i > 2000) { quit <- true } } Go
  • 18. ORC: University of Texas, Augustin. 2009 - …. All values are streaming, all calls are concurrent Concurrency combinators: • A | B (parallel execution) • {| A |} (wait until first value will arrive in a) • A; B (A then B ) • A > x > B (spawn B on each value from x from A) • A>>B (if we need no x value).
  • 19. Orc Example: def min((n1,q1), (n2,q2)) =     Ift(q1 <= q2) >> (n1, q1)   | Ift(q2 <: q1) >> (n2, q2) -- Return the best quote at or under $200 -- received within 15 seconds def bestQuote([]) = ("None of the above", 200) def bestQuote(airline:rest) =     val best = bestQuote(rest)     val current = airline() | Rwait(15000) >> best     min(current, best) bestQuote([Airline("Delta"),            Airline("United")])
  • 20. Scala: Lets’ emulate all N flavors. ❖ Foundations: ❖ Functional (std libs, scalaz-streams, fs2, .. spark) ❖ Rx (akka-streams, monix) ❖ CSP (scala-gopher, subscript) ❖ Implementations: ❖ Pull (scalaz-streams, fs2, Rx cold) ❖ Push [+ flow control] (akka, Rx hot) ❖ Active-Channels (gopher)
  • 21. Functional Streaming: Ideas:Pull ❖ Pull ❖ step 0 (std: scala: provide generation function, which called on reading element) ❖ step 1 (next element => (element | end | error)) ❖ step 2 - emit more than one element (called function return element generator) ❖ step 3 - combine and add pull generator.
  • 22. Functional Streaming: Ideas:Pull ❖ Pull ❖ step 0 (std: scala: provide generation function, which called on reading element) ❖ step 1 (next element => (element | end | error)) ❖ step 2 - emit more than one element (called function return element generator) ❖ step 3 - combine and add pull generator. SNil ::: ( => T) def gen(n):Stream[Int] = { n :: gen(n+1) }
  • 23. Functional Streaming: :Pull ❖ Pull ❖ step 1 (next element => (element | end | error)) ❖ step 2 - emit more than one element (called function return element generator) SNil sealed trait Out[-T] ::: ( => Out[T] ) Error, End, Element[T] def gen(n,m):Stream1[Int] = { if (n==m) End else n ::: gen(n+1) }
  • 24. Functional Streaming: Ideas:Pull ❖ Pull ❖ step 2 - emit more than one element (called function return element) ❖ t generator) SNil trait Pull ::: ( => Pull[T] ) Pull.error, Pull.end, Pull.emit(t1, t2) Pull.flatMap(otherPull)
  • 25. Functional Streaming: Ideas:Pull ❖ Pull ❖ step 3 — wrap output in a monad [ usually: Task ] ❖ t generator) SNil trait Pull ::: ( => Pull[M,T,S] ) Pull.error, Pull.end[S], Pull.emit(t1, t2) Pull.flatMap(otherPull) stream.run stream.eval(…)
  • 26. Functional Streaming: Ideas:Pull ❖ Pull ❖ step N — pull combinators running in transformer. ❖ t generator) + states, + stream combinators def nextS(n: Int, f: (Int) => Boolean):fs2.Stream[Pure, Int] = { if (f(n)) fs2.Stream(n) ++ nextS(n+1, x => f(x) && x % n != 0) else nextS(n+1, f)
  • 27. Functional Streaming: Ideas:Pull ❖ Pull problem: need to know computation semantics exactly ❖ t generator) def simple(from: Int): fs2.Stream[Pure, Int] = fs2.Stream(from) ++ simple(from + 1).lter(n => n % from!= 0) def nextS(n: Int, f: (Int) => Boolean):fs2.Stream[Pure, Int] = { if (f(n)) fs2.Stream(n) ++ nextS(n+1, x => f(x) && x % n != 0) else // easy, correct, but inefficient.
  • 28. Functional Streaming: Ideas:Push ❖ Push ❖ step 0: provide function, which our stream will call and run for starting data flow process. ❖ step 1: provide ‘back’ callback for flow control. ❖ step 2: hide complexity by providing set of built-in combinators ❖ step 4: create data flow DSL on top of this. ❖ step 5: decouple generation of running functions from DSL ❖ representation (materialize), Akka.
  • 29. Functional Streaming: Ideas:Push ❖ Push ❖ step 0: provide function, which our stream will call ❖ step 1: provide ‘back’ callback for flow control. ❖ ste ❖ p 2: hide complexity by providing set of built-in combinators ❖ step 4: create data flow DSL on top of this. trait PushStream0[T] { def subscribe( onNext: T => Unit, onEnd: Unit => Unit, onError: Unit => Unit, ): PushSubscription0 }
  • 30. Functional Streaming: Ideas:Push ❖ Push ❖ step 1: provide ‘back’ callback for flow control. ❖ ste ❖ p 2: hide complexity by providing set of built-in co ❖ mbinators ❖ step 4: create data flow DSL on top of this. trait PushStream1[T] { def subscribe( onNext: (T, OutHandler) => Unit, onEnd: OutHandler => Unit, onError: OutHandler => Unit, ): PushSubscription1 } trait OutHandler { def onPull() def onFinish()
  • 31. Functional Streaming: Ideas:Push ❖ Push ❖ step 2: hide complexity by providing set of built-in combinators ❖ step 4: create data flow DSL on top of this. val process = stream.map(_.aXribute(model)) .lter(_.p > limit) .truffle(3000, 1 second)(_.dropLast). . aggregate(average) .saveToDb(ctx) process.run() // Rx —- near 80 combinators // akka-streams —- near ???
  • 32. Functional Streaming: Ideas:Push ❖ Push ❖ step 4: [akka] create data flow DSL. ❖ advInput ~> aXribute ~> lterByLocation ~> retrieweProle ~> advert locationInput ~> lterByLocation
  • 33. Functional streaming: Active channel Write callback // if writer exists Read callback //if reader exists Corner cases: - Unbuffered channel - Unlimited buffer
  • 34. scala-gopher ❖ Akka extension + Macros on top of SIP22-async ❖ Integrate CSP Algebra and scala concurrency primitives ❖ Provides: ❖ asynchronous API inside general control-flow ❖ pseudo-synchronous API inside go{ .. } or async{ ..} blocks ❖ Techreport: goo.gl/dbT3P7
  • 35. def nPrimes(n:Int):Future[List[Int]]= { val in = makeChannel[Int]() val out = makeChannel[Int]() go { for(i <- 1 to Int.MaxValue) in.write(i) } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } } go { for(i <- 1 to n) yield out.read } }
  • 36. def nPrimes(n:Int):Future[List[Int]]= { val in = makeChannel[Int]() val out = makeChannel[Int]() go { for(i <- 1 to n*n) out.write(i) } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } } go { for(i <- 1 to n) yield out.read } } go { for(i <- 1 to Int.MaxValue) in.write(i) }
  • 37. def nPrimes(n:Int):Future[List[Int]]= { val in = makeChannel[Int]() val out = makeChannel[Int]() go { for(i <- 1 to Int.MaxValue) in.write(i) } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } } go { for(i <- 1 to n) yield out.read } } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } }
  • 38. def nPrimes(n:Int):Future[List[Int]]= { val in = makeChannel[Int]() val out = makeChannel[Int]() go { for(i <- 1 to Int.MaxValue) in.write(i) } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } } go { for(i <- 1 to n) yield out.read } } go { for(i <- 1 to n) yield out.read }
  • 39. def nPrimes(n:Int):Future[List[Int]]= { val in = makeChannel[Int]() val out = makeChannel[Int]() go { for(i <- 1 to Int.MaxValue) in.write(i) } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } } go { for(i <- 1 to n) yield out.read } }
  • 40. Goroutines ❖ go[X](body: X):Future[X] ❖ Wrapper around async + ❖ translation of high-order functions into async form ❖ handling of defer statement
  • 41. go { (1 to n).map(i => out.read) } - async: translate ‘pseudo-synchonic’ code into asynchronous non-blocking form. - go: translate invocation of synchronic hight-order functions into asynchronous one val sum(a:Future[Int],b:Future[Int]):Future[Int]= async{ await(a) + await(b) } // SIP 22 // have stable implementation, but not finished yet. val sum(a:Future[Int],b:Future[Int]):Future[Int]= { var sm = new class StateMachine122 { var (fa,ra,fb,rb,r,s) = (a,Int(),b,Int(),0) def apply():Future[Unit] = s.state match { case 0 => fa.map{ x => a=x; s = 1; apply() } case 1 => fb.map{ x => b=x; s = 2; apply() } case 2 => r = ra + rb } }. apply() map (_ => sm.r) }
  • 42. go { (1 to n).map(i => out.read) } - async: translate ‘pseudo-synchonic’ code into asynchronous non-blocking form. - go: translate invocation of synchronic hight-order functions into asynchronous one val sum(a:Future[Int],b:Future[Int]):Future[Int]= async{ await(a) + await(b) } // SIP 22 // have stable implementation, but not finished yet. // want asynchronous read inside map // Can’t work with expressions inside hight-order functions, like map
  • 43. Goroutines ❖ translation of hight-order functions into async form ❖ f(g): f: (A=>B)=>C in g: A=>B, ❖ g is invocation-only in f iff ❖ g called in f or in some h inside f : g invocation-only in h ❖ g is ❖ not stored in memory behind f ❖ not returned from f as return value ❖ Collection API high-order methods are invocation-only
  • 44. Translation of invocation-only functions ❖ f: ((A=>B)=>C), g: (A=>B), g invocation-only in f ❖ f’: ((A=>Future[B])=>Future[C]) g’: (A=>Future[B]) ❖ await(g’) == g => await(f’) == f ❖ f’ => await[translate(f)] ❖ g(x) => await(g’(x)) ❖ h(g) => await(h’(g’)) iff g is invocation-only in h ❖ That’s all ❖ (implemented for specic shapes and parts of scala collection API)
  • 45. def nPrimes(n:Int):Future[List[Int]]= { val in = makeChannel[Int]() val out = makeChannel[Int]() go { for(i <- 1 to n*n) in.write(i) } go { select.fold(in){ (ch,s) => s match { case p:ch.read => out.write(p) ch.filter(_ % p != 0) } } } go { for(i <- 1 to n) yield out.read } } go { for(i <- 1 to n) yield out.read }
  • 46. go { (1 to n).map(i => out.read) } async{ await(t[(1 to n).map(i => out.read)]) } async{ await((1 to n).mapAsync(t[i => async(out.read)])) } async{ await((1 to n).mapAsync(i => async(await(out.aread))) } (1 to n).mapAsync(i => out.aread)
  • 47. Channels ❖ Channel[A] <: Input[A] + Output[A] ❖ Unbuffered ❖ Buffered ❖ Dynamically growing buffers [a-la actor mailbox] ❖ One-time channels [Underlaying promise/Future] ❖ Custom CSP
  • 48. Input[A] - internal API trait Input[A] { type read = A def cbread(f: ContRead[A,B]=>Option[ ContRead.In[A] => Future[Continuated[B]]) ….. } case class ContRead[A,B]( function: F, channel: Channel[A], flowTermination: FlowTermination[B] ) // in ConRead companion object sealed trait In[+A] case class Value(a:A) extends In[A] case class Failure(ex: Throwable] extends In[Nothing] case object Skip extends In[Nothing] case object ChannelClosed extends In[Nothing] ContRead[A,B].F Continuated[B] • ContRead • ContWrite • Skip • Done • Never
  • 49. Input[A] - external API trait Input[A] { …… def aread: Future[A] = <implementation…> def read: A = macro <implementation … > …. def map[B](f: A=>B): Input[B] = …. // or, zip, lter, … etc await(aread) + usual operations on streams in functional language
  • 50. Output[A] - API trait Output[A] { type write = A def cbwrite(f: ContWrite[A,B]=>Option[ (A,Future[Continuated[B]])], ft: FlowTermination[B]) ….. def awrite(a:A): Future[A] = …. def write(a:A): A = …. << await(awrite) …. ContWrite[A,B].F case class ContWrite[A,B]( function: F, channel: Channel[A], flowTermination: FlowTermination[B] )
  • 51. Selector ss go { for{ select{ case c1 -> x : … // P case c2 <- y : … // Q } } Go language: go { select.forever { case x : c1.read => … // P case y : c2.write => … // Q } } Scala: Provide set of flow combinators: forever, once, fold select.aforever { case x : c1.read => … // P case y : c2.write => … // Q }
  • 52. select: fold API def bonacci(c: Output[Long], quit: Input[Boolean]): Future[(Long,Long)] = select.afold((0L,1L)) { case ((x,y),s) => s match { case x: c.write => (y, x+y) case q: quit.read => select.exit((x,y)) } } fold/afold: • special syntax for tuple support • ’s’: selector pseudoobject • s match must be the first statement • select.exit((..)) to return value from flow
  • 53. Transputer ❖ Actor-like object with set of input/output ports, which can be connected by channels ❖ Participate in actor systems supervisors hierarchy ❖ SelectStatement ❖ A+B (parallel execution, common restart) ❖ replicate
  • 54. Transputer: select class Zipper[T] extends SelectTransputer { val inX: InPort[T] val inY: InPort[T] val out: OutPort[(T,T)] loop { case x: inX.read => val y = inY.read out write (x,y) case y: inY.read => val x = inX.read out.write((x,y)) } } inX inY out
  • 55. Transputer: replicate val r = gopherApi.replicate[SMTTransputer](10) ( r.dataInput.distribute( (_.hashCode % 10 ) ). .controlInput.duplicate(). out.share() ) dataInput controlInput share
  • 56. Programming techniques ❖ Dynamic recursive dataflow schemas ❖ conguration in state ❖ Channel-based two-wave generic API ❖ expect channels for reply
  • 57. Dynamic recursive dataflow select.fold(output){ (out, s) => s match { case x:input.read => select.once { case x:out.write => case select.timeout => control.distributeBandwidth match { case Some(newOut) => newOut.write(x) out | newOut case None => control.report("Can't increase bandwidth") out } } case select.timeout => out match { case OrOutput(frs,snd) => snd.close frs case _ => out } } dynamically increase and decrease bandwidth in dependency from load
  • 58. Dynamic recursive dataflow select.fold(output){ (out, s) => s match { case x:input.read => select.once { case x:out.write => case select.timeout => control.distributeBandwidth match { case Some(newOut) => newOut.write(x) out | newOut case None => control.report("Can't increase bandwidth") out } } case select.timeout => out match { case OrOutput(frs,snd) => snd.close frs case _ => out } } dynamically increase and decrease bandwidth in dependency from load case select.timeout => control.distributeBandwidth match { case Some(newOut) => newOut.write(x) out | newOut case None => control.report("Can't increase bandwidth") out
  • 59. Dynamic recursive dataflow select.fold(output){ (out, s) => s match { case x:input.read => select.once { case x:out.write => case select.timeout => control.distributeBandwidth match { case Some(newOut) => newOut.write(x) out | newOut case None => control.report("Can't increase bandwidth") out } } case select.timeout => out match { case OrOutput(frs,snd) => snd.close frs case _ => out } } dynamically increase and decrease bandwidth in dependency from load case select.timeout => out match { case OrOutput(frs,snd) => snd.close frs case _ => out }
  • 60. Channel-based generic API ❖ Endpoint instead function call ❖ f: A=>B; af: A => Future[B] ❖ endpoint: Channel[A,Channel[B]] ❖ Recursive ❖ case class M(A,Channel[M]) ❖ f: (A,M) => M (dataflow congured by input)
  • 61. Channel-based generic API trait Broadcast[T] { val listeners: Output[Channel[T]] val messages: Output[T] def send(v:T):Unit = { messages.write(v) } …. • message will received by all listeners
  • 62. Channel-based generic API class BroadcastImpl[T] { val listeners: Channel[Channel[T]] val messages: Channel[T] = makeChannel[Channel[T]] def send(v:T):Unit = { messages.write(v) } …. } // private part case class Message(next:Channel[Message],value:T) select.afold(makeChannel[Message]) { (bus, s) => s match { case v: messages.read => val newBus = makeChannel[Message] current.write(Message(newBus,v)) newBus case ch: listeners.read => select.afold(bus) { (current,s) => s match { case msg:current.read => ch.awrite(msg.value) current.write(msg) msg.next } } current
  • 63. Channel-based generic API val listeners: Channel[Channel[T]] val messages: Channel[T] = makeChannel[] // private part case class Message(next:Channel[Message],value:T) select.afold(makeChannel[Message]) { (bus, s) => s match { case v: message.read => val newBus = makeChannel[Message] current.write(Message(newBus,v)) newBus case ch: listener.read => select.afold(bus) { (current,s) => s match { case msg:current.read => ch.awrite(msg.value) current.write(msg) msg.next } } • state - channel [bus], for which all listeners are subscribed • on new message - send one to bus with pointer to the next bus state • listener on new message in bus - handle, change current and send again • on new listener - propagate
  • 64. Channel-based generic API val listener: Channel[Channel[T]] val message: Channel[T] = makeChannel[] // private part case class Message(next:Channel[Message],value:T) select.afold(makeChannel[Message]) { (bus, s) => s match { case v: message.read => val newBus = makeChannel[Message] current.write(Message(newBus,v)) newBus case ch: listener.read => select.afold(bus) { (current,s) => s match { case msg:current.read => ch.awrite(msg.value) msg.next } } current • state - channel [bus], for which all listeners are subscribed • on new message - send one to bus with pointer to the next bus state • listener on new message in bus - handle, change current and send again • on new listener - propagate s match { case msg:current.read => ch.awrite(msg.value) current.write(msg) msg.next }
  • 65. Channel-based generic API val listener: Channel[Channel[T]] val message: Channel[T] = makeChannel[] // private part case class Message(next:Channel[Message],value:T) select.afold(makeChannel[Message]) { (bus, s) => s match { case v: message.read => val newBus = makeChannel[Message] current.write(Message(newBus,v)) newBus case ch: listener.read => select.afold(bus) { (current,s) => s match { case msg:current.read => ch.awrite(msg.value) current.write(msg) msg.next } } current • state - channel [bus], for which all listeners are subscribed • on new message - send one to bus with pointer to the next bus state • listener on new message in bus - handle, change current and send again • val newBus = makeChannel[Message] current.write(Message(newBus,v)) newBus
  • 66. Adoption: first lessons. ❖ Fluent inline API vs OO ❖ select folds are more popular than creating transputer classes. ❖ In-place handling for ❖ end of streams. ❖ errors.
  • 67. error handling inside select val f = select.afold(s0) { (x, s) => s match { case v: channel.read => doSomeProcessing(x,v) case v: channel.done => doCleanup(x) select.exit(x) case ex: select.error => if (canContinue(ex)) { logError(ex) x } else throw ex case t: select.timeout => doSomethingWithTimeout() .. } // vs recreation of fold in future
  • 68. Scala concurrency libraries Flexibility Scalability Level Actors • Actors • low level, • great flexibility and scalability • Akka-Streams • low flexibility • hight-level, scalable • SCO • low scalability • hight-level, flexible • Reactive Isolated • hight-level, scalable, • allows delegation • Gopher • can emulate each style Streams SCO Subscript Language
  • 69. Scala-Gopher: Conclusion ❖ Native integration of CSP into Scala is possible ❖ have a place in a Scala concurrency model zoo ❖ Bring well-established techniques to Scala world ❖ (recursive dataflow schemas; channel API) ❖ Translation of invocation-only high-order functions into async form can be generally recommended. ❖ (with TASTY transformation inside libraries can be done automatically)
  • 70. Thanks for attention ❖ Questions ? ❖ https://github.com/rssh/scala-gopher ❖ ruslan shevchenko: ruslan@shevchenko.kiev.ua