implementation of 'go'-like language constructions in scala (russian)
Upcoming SlideShare
Loading in...5
×
 

implementation of 'go'-like language constructions in scala (russian)

on

  • 625 views

Presentation for http://kievfprog.net about implementation of go-like language constructions in scala: https://github.com/rssh/scala-gopher

Presentation for http://kievfprog.net about implementation of go-like language constructions in scala: https://github.com/rssh/scala-gopher

Statistics

Views

Total Views
625
Views on SlideShare
606
Embed Views
19

Actions

Likes
0
Downloads
5
Comments
0

1 Embed 19

https://twitter.com 19

Accessibility

Categories

Upload Details

Uploaded via as OpenOffice

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

implementation of 'go'-like language constructions in scala (russian) implementation of 'go'-like language constructions in scala (russian) Presentation Transcript

  • Go / Scala Реализация конструкций языка Go в Scala Руслан Шевченко <ruslan@shevchenko.kiev.ua> https://github.com/rssh/scala-gopher
  • Что такое в go ?  области видимости (scope)  ( defer/ panic / destroy )  параллелизм  channels  select statement  Отличие от 'родного' подхода в scala  Как реализовать 'go' вариант Что дальше ...
  • С defer 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(); } } По старому:
  • Традиционно: 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
  • try try try finally finally finally op/defer
  • Как это реализовано в scala:  Макросы  Передача параметров по имени  Традиционный try/cath goScope = .... (macro, в котором переписывается аргумент) 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]() } Без сахара:
  • 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 ? ?! ?? Write go: channel <- x Scala: channel <~ x channel ! x !! (немедленно) !? (через таймоут)
  • Select Каналы соединяют потоки исполнения
  • go func() { for { select { case msg1 := <- c1: fmt.Println(msg1) case msg2 := <- c2: fmt.Println(msg2) } } }() Go: типичный паттерн: select внутри for внутри goroutine
  • go for(s <- select) s match { case c1 ~> (msg1: Msg1Type) => println(msg1) case c2 ~>(msg2:Msg2Type) => println(msg2) } Scala аналог: - реализован как макрос foreach - ~> в образце: надо указывать тип - активная очередь Открытый вопрос: хороший “родной” не-макро синтаксис
  • Без сахара (упрощенно) [1]: go { val s = new SelectContext(); s.addReader(c1) { (msg1:Msg1Type) => println(msg1) } s.addReader(c2) { (msg2:Msg2Type) => println(msg2) } s.run() }
  • Без сахара (упрощенно) [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() } (Дальнейшая работа) S
  • 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
  • Текущая внутренняя реализация:  Активная очередь  Channel = [Blocked Query + Execution Context ] • Select: координационные примитивы + wait [oops...] – Count down latch – Memory barrier  Расширения по сравнению с моделью Go  Асинхронные операции  Остановка контекста (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) Channels (как в go)  Реактивные  Неблокирующие операции  Запрос/Ответ парадигма  При перегрузке - mailbox overflow при send  Что-то обработать.  Потоково ориентированные  Wait это нормально (переключение потоков в это время)  Однонаправленная труба  При перегрузке ожидание при send  Что-то посчитать
  • x1, x2, x3, ............ x1*y1, x2*y2, x3*y3, ............ y1, y2, y3, ............ go { while(;) { val x = channelX ? val y = channelY ? channelZ ! x*y } } Пример: Легко с gopher, сложно с Akka
  • bindWrite bindRead ? [блокирующие операции в акторе]
  • Что дальше  Новый “базис” [select in loop in go] - слишком фундаментально, что бы быть комбинацией 3-х конструкций.  Альтернативный синтаксис с явной реактивностью  Заставить работь вывод типов  Подключаемые (pluggable) реализации  Оптимизировать крайние случаи
  • Подключаемые реализации.  Существует много стратегий. (текущая реализация не лучшая) – Schedule/callback вместо waits – Собственный dispatcher – ..... Тесты производительности, Цикл “прототипирование / тест” Проблемы - отсутсвие механизма импорта модулей @exported import - JVM Помощь сообщества (?)
  • Переписывание в реактивную форму - Процесс, аналогичный СPS - но легче
  • 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 ?) } Такая же проблема, как и с CPS: - foldLeft не наш. - foreach не наш и непонятно, что там for(x <- something) channel <~~ x отсуствие поддержки сопрограмм в JVM
  • Поддержка сопрограм в JVM - Изменение JVM - Переписывание байт-кода - Ничего не делать – thread pool большой (нагрузить wait выполнением заведомо неблокирующих задач)
  • The Da Vinci machine http://openjdk.java.net/projects/mlvm/index.html AVIAN VM http://oss.readytalk.com/avian/
  • Когда нибудь – все будет хорошо. а пока – вот вам котик
  • Continuations: Bytecode rewriting. Frames: a) Вместо возрата – копируем фрейм. foldLeft ? channel + *
  • Continuations: Bytecode rewriting. Frames: foldLeft + *
  • Continuations: Bytecode rewriting. Frames: Suspended Применение CPS к байт-коду foldLeft + * Channel ?
  • Помощь сообщества. https://github.com/rssh/scala-gopher  Примеры использования.  Инструментирование и профилирование  Лучшие реализации . Давайте подумаем вместе. Спасибо за внимание. Ruslan Shevchenko <Ruslan@Shevchenko.Kiev.UA>