Upload
ruslan-shevchenko
View
276
Download
0
Tags:
Embed Size (px)
DESCRIPTION
Presentation about implementation of go-like language constructions in scala: https://github.com/rssh/scala-gopher
Citation preview
Go / Scala
Implementation of go language constructions in scala
Ruslan Shevchenko<[email protected]>
https://github.com/rssh/scala-gopher
Whats in go ?
scope ( defer/ panic / destroy )
parallelism channels select statement
Differences from 'native' scala approach How to implement go variant
Future directions...
Scope
def copy(inf: File, outf: File): Long = goScope { val in = new FileInputStream(inf) defer{ in.close() } val out = new FileOutputStream(outf); defer{ out.close() } out.getChannel() transferFrom(in.getChannel(), 0, Long.MaxValue) }
def copy(inf: File, outf: File): Long = { val in = new FileInputStream(inf) try { val out = new FileOutputStream(outf) try { out.getChannel() transferFrom(in.getChannel(), 0, Long.MaxValue) } finally { out.close(); } } finally { in.close(); }}
Old way:
Traditional way:
def copy(inf: File, outf: File): Long = { val in = new FileInputStream(inf) try { val out = new FileOutputStream(out) try { out.getChannel() transferFrom(in.getChannel(), 0,Long.MaxValue) } finally { out.close(); } } finally { in.close(); }}
def copy(inf: File, outf: File): Long = goScope { val in = new FileInputStream(inf) defer{ in.close() } val out = new FileOutputStream(outf); defer{ out.close() } out.getChannel() transferFrom(in.getChannel(), 0, Long.MaxValue) }
Go way
try
try
try
finally
finally
finally
op/defer
How this done is scala:
Macroses Call-by-name-params Traditional try/cath
goScope = .... (macro wich rewrite arg)
defer => @compileTimeOnly
def copy(inf: File, outf: File): Long = { val sc0 = new ScopeContext(); sc0.eval { val in = new FileInputStream(inf) sc0.pushDefer{ in.close() } val out = new FileOutputStream(outf); sc0.pushDefer{ out.close() } out.getChannel() transferFrom(in.getChannel(), 0, Long.MaxValue) } sc0.unwindDefers[Long]() }
Unsugared:
Scope: defer / panic / recover
panic => throw new PanicException() Recover => return
try { ....} catch { case ex: Exception => return x}
defer{ ......... recover(x)}
Channels
Read:
go: channel -> x
Scala: channel ~> x x = channel ? ?! ??
Writego: channel <- x
Scala: channel <~ x channel ! x !! (immediatly) !? (with timeout)
Select
Channels connect execution flows
go func() { for { select { case msg1 := <- c1: fmt.Println(msg1) case msg2 := <- c2: fmt.Println(msg2) } } }()
Go: typical pattern: select inside for inside goroutine
go for(s <- select) s match { case c1 ~> (msg1: Msg1Type) => println(msg1) case c2 ~>(msg2:Msg2Type) => println(msg2) }
Scala Analog:
- implemented as foreach macros- ~> pattern: require typing- active queue
Open question: native non-macro syntax
Unsugared (simplicified) [1]:
go { val s = new SelectContext(); s.addReader(c1) { (msg1:Msg1Type) => println(msg1) } s.addReader(c2) { (msg2:Msg2Type) => println(msg2) } s.run()}
Unsugared (simplicified) [2]:
val scope = new ScopeContext(); val s = new SelectContext();Future { s.addReader(c1) { (msg1:Msg1Type) => println(msg1) } s.addReader(c2) { (msg2:Msg2Type) => println(msg2) }} map { s.runUnblocked() } map { scope.finish() }
(Future work)
S
Just select:
for(s <- select.once) s match { case c1 ~> (msg1: Msg1Type) => println(msg1) case c2 ~>(msg2:Msg2Type) => println(msg2) }
select { case msg1 := <- c1: fmt.Println(msg1) case msg2 := <- c2: fmt.Println(msg2)}
GO
SCALA
Internal implementation:
Active channel Channel = [Blocked Query + Execution Context ]
Coordination primitives + wait for select Count down latch Memory barrier
Extensions over Go model async operations context shutdown.
val consumer = go { for(s <- select) { s match { case `channel` ~> (i:Int) => sum = sum + i if (i==1000) s.shutdown() } } sum }
Future[Int]
Akka (Erlang-like actors)
Channels (go-like)
Reactive No blocking operations
Request/Reply paradigm.
Mailbox overflow on overload
Handle something.
Flow oriented Wait is normal (switch during wait) One-direction pipe paradigm
wait on send On overload
Compute something
x1, x2, x3, ............
x1*y1, x2*y2, x3*y3, ............
y1, y2, y3, ............
go { while(;) { val x = channelX ? val y = channelY ? channelZ ! x*y }}
Example: Easy with channels, hard with Akka
bindWritebindRead
? [blocking operation]
Future directions
Redefining of base primitivies [select in loop in go] is too fundamental, to be combination of 3 constructions.
Native non-macro syntax Make scala type inference works
Pluggable implementations Optimize corner cases
Pluggable implementations.
Exists many strategies. (current implemented is not best)
Schedule/callback instead waits Play with own dispatcher .....
Performance tests, Implement/Prototype/Test loop,
Problems: Lack of import-based configuration in scala @exported import
Community help needed.
Rewriting blocking API into reactive
- like CPS (continuations passing style)
go { ... val x = channelX ? val y = channelY ? channelZ ! x*y ...} go { .....
channelX.read map { x => channelY.read map { y => channelZ.write map { ch => ch <~! x*y } } } }}
someCollection foldLeft { (s,x) => s + (x* channel ?) }
Problem – same as with CPS: - foldLeft – implemented not here.
- foreach
for(x <- something) channel <~~ x
Continuations not supported directly by JVM
Continuations in JVM
- Patched JVM - Byte-code rewriting. - Do nothing – thread pools now big (utilize wait by running Flow of non-blocking tasks here)
The Da Vinci machine
http://openjdk.java.net/projects/mlvm/index.html
AVIAN VM
http://oss.readytalk.com/avian/
Someday everything will be fine. For now - here is a cat
Continuations: Bytecode rewriting.
Frames:
Let's save frame during function end, instead deleting one.
foldLeft
? channel
+
*
Continuations: Bytecode rewriting.
Frames:
foldLeft
+
*
Continuations: Bytecode rewriting.
Frames:
Suspended
CPS transformation on bytecode level
foldLeft
+
*
Channel ?
Community help needed.
https://github.com/rssh/scala-gopher
Build examples of typical usage. Instrument ones for performance tests Provide better implementations.
Let's think together. Thanks for attention.
Ruslan Shevchenko <[email protected]>