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

735 views

Published on

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

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
735
On SlideShare
0
From Embeds
0
Number of Embeds
15
Actions
Shares
0
Downloads
7
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

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

  1. 1. Go / Scala Реализация конструкций языка Go в Scala Руслан Шевченко <ruslan@shevchenko.kiev.ua> https://github.com/rssh/scala-gopher
  2. 2. Что такое в go ?  области видимости (scope)  ( defer/ panic / destroy )  параллелизм  channels  select statement  Отличие от 'родного' подхода в scala  Как реализовать 'go' вариант Что дальше ...
  3. 3. С 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(); } } По старому:
  4. 4. Традиционно: 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(); } }
  5. 5. 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
  6. 6. try try try finally finally finally op/defer
  7. 7. Как это реализовано в scala:  Макросы  Передача параметров по имени  Традиционный try/cath goScope = .... (macro, в котором переписывается аргумент) defer => @compileTimeOnly
  8. 8. 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]() } Без сахара:
  9. 9. Scope: defer / panic / recover  panic => throw new PanicException()  Recover => return try { .... } catch { case ex: Exception => return x } defer{ ......... recover(x) }
  10. 10. Channels Read: go: channel -> x Scala: channel ~> x x = channel ? ?! ?? Write go: channel <- x Scala: channel <~ x channel ! x !! (немедленно) !? (через таймоут)
  11. 11. Select Каналы соединяют потоки исполнения
  12. 12. go func() { for { select { case msg1 := <- c1: fmt.Println(msg1) case msg2 := <- c2: fmt.Println(msg2) } } }() Go: типичный паттерн: select внутри for внутри goroutine
  13. 13. go for(s <- select) s match { case c1 ~> (msg1: Msg1Type) => println(msg1) case c2 ~>(msg2:Msg2Type) => println(msg2) } Scala аналог: - реализован как макрос foreach - ~> в образце: надо указывать тип - активная очередь Открытый вопрос: хороший “родной” не-макро синтаксис
  14. 14. Без сахара (упрощенно) [1]: go { val s = new SelectContext(); s.addReader(c1) { (msg1:Msg1Type) => println(msg1) } s.addReader(c2) { (msg2:Msg2Type) => println(msg2) } s.run() }
  15. 15. Без сахара (упрощенно) [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
  16. 16. 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
  17. 17. Текущая внутренняя реализация:  Активная очередь  Channel = [Blocked Query + Execution Context ] • Select: координационные примитивы + wait [oops...] – Count down latch – Memory barrier  Расширения по сравнению с моделью Go  Асинхронные операции  Остановка контекста (context shutdown).
  18. 18. val consumer = go { for(s <- select) { s match { case `channel` ~> (i:Int) => sum = sum + i if (i==1000) s.shutdown() } } sum } Future[Int]
  19. 19. Akka (как в Erlang) Channels (как в go)  Реактивные  Неблокирующие операции  Запрос/Ответ парадигма  При перегрузке - mailbox overflow при send  Что-то обработать.  Потоково ориентированные  Wait это нормально (переключение потоков в это время)  Однонаправленная труба  При перегрузке ожидание при send  Что-то посчитать
  20. 20. 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
  21. 21. bindWrite bindRead ? [блокирующие операции в акторе]
  22. 22. Что дальше  Новый “базис” [select in loop in go] - слишком фундаментально, что бы быть комбинацией 3-х конструкций.  Альтернативный синтаксис с явной реактивностью  Заставить работь вывод типов  Подключаемые (pluggable) реализации  Оптимизировать крайние случаи
  23. 23. Подключаемые реализации.  Существует много стратегий. (текущая реализация не лучшая) – Schedule/callback вместо waits – Собственный dispatcher – ..... Тесты производительности, Цикл “прототипирование / тест” Проблемы - отсутсвие механизма импорта модулей @exported import - JVM Помощь сообщества (?)
  24. 24. Переписывание в реактивную форму - Процесс, аналогичный СPS - но легче
  25. 25. 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 } } } } }
  26. 26. someCollection foldLeft { (s,x) => s + (x* channel ?) } Такая же проблема, как и с CPS: - foldLeft не наш. - foreach не наш и непонятно, что там for(x <- something) channel <~~ x отсуствие поддержки сопрограмм в JVM
  27. 27. Поддержка сопрограм в JVM - Изменение JVM - Переписывание байт-кода - Ничего не делать – thread pool большой (нагрузить wait выполнением заведомо неблокирующих задач)
  28. 28. The Da Vinci machine http://openjdk.java.net/projects/mlvm/index.html AVIAN VM http://oss.readytalk.com/avian/
  29. 29. Когда нибудь – все будет хорошо. а пока – вот вам котик
  30. 30. Continuations: Bytecode rewriting. Frames: a) Вместо возрата – копируем фрейм. foldLeft ? channel + *
  31. 31. Continuations: Bytecode rewriting. Frames: foldLeft + *
  32. 32. Continuations: Bytecode rewriting. Frames: Suspended Применение CPS к байт-коду foldLeft + * Channel ?
  33. 33. Помощь сообщества. https://github.com/rssh/scala-gopher  Примеры использования.  Инструментирование и профилирование  Лучшие реализации . Давайте подумаем вместе. Спасибо за внимание. Ruslan Shevchenko <Ruslan@Shevchenko.Kiev.UA>

×