• Like
Курсы актерского мастерства
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

Курсы актерского мастерства

  • 4,085 views
Published

Презентация "Курсы актерского мастерства", которая была сделана на первоей встреча энтузиастов Scala Беларуси.

Презентация "Курсы актерского мастерства", которая была сделана на первоей встреча энтузиастов Scala Беларуси.

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
  • Презентация, которая была сделана на первой встрече энтузиастов языка программирования Scala Беларуси.

    http://twitter.com/#!/scalaby
    http://groups.google.com/group/scala-enthusiasts-belarus
    Are you sure you want to
    Your message goes here
No Downloads

Views

Total Views
4,085
On SlideShare
0
From Embeds
0
Number of Embeds
3

Actions

Shares
Downloads
27
Comments
1
Likes
2

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Школа актерского мастерства @remeniuk
  • 2. • 70-ые, концепция «Актеров»• 80-ые, Erlang, популяризация и развитие – OTP – фреймворк для создания надежных систем, толерантных к ошибкам• 00-ые, Scala, cовременное представление
  • 3. Почему актеры?• Параллелизм без страха• Хороший дизайн• Простая расширяемость – location transparency WIN!• Инструментарий для создания надежных систем
  • 4. • scala.actors• Akka• Scalaz• Kilim• Lift
  • 5. Будущее: scala.actors + AkkaКак будет происходить объединение scala.actors иAkka?Предположение: единый API, и fault-toleranceстек из Akka.
  • 6. scala.actorsThread-based Event-drivenactor{ actor{ while(true){ loop{ receive{ react{ case msg => case msg => } } } }} } ! !! !? ?
  • 7. Актер с состоянием
  • 8. Актер с состоянием• Модель publisher/subscriber – тривиальный подход - хранение в переменной protected var subscribers = List[Subscriber]() loop { react{ case AddSubscriber(subscriber) => subscribers = subscriber :: subscribers case Publish(event) => subscribers.foreach(_ ! event)
  • 9. Хранение состояния в ErlangПередача состояния в рекурсии:• «чистый» функциональный подход• требует поддержки оптимизации рекурсии loop(State) -> receive Msg -> NewState = whatever(Msg), loop(NewState) end.
  • 10. Модель publisher/subscriber• Передача состояния в рекурсии def loop(subscribers: List[Subscriber]): Unit = react{ case AddSubscriber(subscriber) => loop(subscriber :: subscribers) case Publish(event) => subscribers.foreach(_ ! event) loop(subscribers) } def act = loop(Nil)
  • 11. Идемпотентный актер
  • 12. Идемпотентный актерАктер, устойчивый к получению дупликатов сообщений f(x) = f(f(x))
  • 13. Nested react/receive (вложенныйобработчик) • обрабатывается только первое сообщение – остальные пропускаютсяloop { react { case Event(evt) => // необходимые вычисления... def skip: Unit = reactWithin(0) { case Event(event) if(event == evt) => skip case TIMEOUT => } skip
  • 14. Nested react/receive способен набольшее:• обработка с приоритетомreactWithin(0){ case Event(evt: String) => subscribers.foreach(_ ! evt) case TIMEOUT => react { case AddSubscriber(subscriber) => subscribers = subscriber :: subscribers case Event(evt) => subscribers.foreach(_ ! evt)
  • 15. Типизированный актер
  • 16. Типизированный актер• Процессы в Erlang не типизированы – Придает гибкость модели • Актеры, по своей природе, динамичны • HotSwap обработчика• Базовые актеры в Scala и Akka, следующие идеологии Erlang, тоже не типизированы
  • 17. Типизированные актеры иногда полезны:• !?, !!, !!! – известный тип «ответа»• специализация обработчиков
  • 18. • Scala <2.7.x - InputChannel[T]• Scala 2.8.x+ - Reactor[T] sealed trait Message class Foo extends Message class Bar extends Message class DatatypeReceiver[T >: Null <: Message] extends Reactor[T] Принимает сообщения подтипа Message
  • 19. Типизация актеров позволяет использоватьвсю мощь системы типов Scala – Typeclass паттернimplicit val fooReceiver = new DatatypeReceiver[Foo]implicit val barReceiver = new DatatypeReceiver[Bar]def send[T >: Null <: Message : DatatypeReceiver] (message: T) = implicitly[DatatypeReceiver[T]] ! messagesend(new Foo) Находит в контексте обработчик нужного типа
  • 20. Альтернативный подход• декларирование возможных типов сообщений в объекте-компаньоне• паттерн Active Object – типизированные актеры в Akka: trait Service { def serve(arg: String) } class ServiceImpl extends TypedActor with Service { def serve(arg: String) = //… } Выполняется service.serve(“foo”) асинхронно
  • 21. Scatter/Gather рассеять/собрать
  • 22. Scatter/Gather рассеять/собрать
  • 23. Тривиальное решение – блокирующий синхронный аггрегатор • аггрегатор не может обрабатывать новые сообщения, пока собирает ответы FAIL! react{ case Event(event) => val results = Futures.awaitAll(1000,reply(res) subscribers.map(_ !! event):_*) // обработка собранных ответов... reply(results)
  • 24. Можно прибегнуть к хитрости – перенестиожидание, обработку и ответ в другой поток• неэффективное использование – выделенный поток просто ждет react{ case Event(event) => actor{ val results = Futures.awaitAll(1000, subscribers.map(_ !! event):_*) // обработка собранных ответов... reply(results) }
  • 25. Aсинхронная аггрегация – решение в Erlang-стиле 1) канал для передачи результатов аггрегации 2) асинхронная сборка результатов: • ответы «рабочих» обрабатываются аггрегатором наравне с другими сообщениями • промежуточные результаты передаются рекурсивно
  • 26. class AsynchAggregator(workers: Iterable[Subscriber],replyChannel: Channel[Any]) extends Actor { def loop(results: List[Any]): Unit = react { case event: Event[Any] => workers foreach(_ ! event); loop(results) reply(Result(res)) case Result(res) => if(results.size != workers.size - 1) loop(res :: results) else { // обработка собранных результатов... replyChannel ! (res :: results); loop(Nil) }
  • 27. Клиентская сторона (синхронное окружение)• клиент ждет сообщение в канале, блокируя потокval aggregator = new AsynchAggregator(subscribers, replyChannel)aggregator ! Event("hello")replyChannel.receive{ case message => // результат работы аггрегатора}
  • 28. Клиентская сторона (синхронное окружение)• клиент ждет сообщение в канале, блокируя потокval aggregator = new AsynchAggregator(subscribers, replyChannel)actor { aggregator ! Event("hello") }replyChannel.receive{ case message => // результат работы аггрегатора}
  • 29. Другие библиотеки• Функциональный подход c Promises в Scalaz• Псевдо-императивный подход с Dataflow в Akka
  • 30. Scalaz Promise[T] Актер-работник асинхронно дает аггрегатору обещание (promise), и выполняет его react { case Message(msg) => val rez = new Promise[String]()(Strategy.Sequential) reply(rez) rez.fulfill{Thread sleep 1000; “Hello!”}}
  • 31. Scalaz Promise[T] Аггрегатор дает клиенту обещание результата, декларируя будущую аггрегацию и обработкуcase msg: Message => val res = workerz.map(worker => (worker !? msg) .asInstanceOf[Promise[String]]) .sequence .map{results => // обработка PROFIT!!! results } List[Promise[String]] => Promise[List[String]] reply(res)
  • 32. Akka DataflowDataflow concurrency – декларативная модельбезопасного параллелизма Dataflow-переменная • Изменение значения вызывает цепную реакцию • Инициализируется единожды • Может безопасно использоваться в многопоточном окружении
  • 33. Akka Dataflow* Dataflow-переменныеdef sample{ val x0, x1, y0, y1 = Promise[Int]() Присвоение значения flow{ y0 << x0() + 1; println("y0 = " + y0()) y1 << x1() + y0(); println("y1 = " + y1()) } flow{ x0 << 1 } flow{ x1 << 2 } scala> sample} y0 = 2 y1 = 4 *базируется на continuations → нет lock’ов
  • 34. Как применить dataflow для scatter /gather?• Рассылка, и асинхронная инициализация dataflow-переменных val result = Promise[String]() val promises = List.fill(recipients.size)(Promise[String]()) recipients.zip(promises).map{case (recipient, promise) => (recipient !!! msg).map{result: String => flow{ promise << result } } }
  • 35. Аггрегаторdef gather(promises: List[CompletableFuture[String]], result: String = ""): String @cps[Future[Any]] = promises match { case head :: tail => gather(tail, head() + result) case Nil => result }flow { result << gather(promises) }
  • 36. Балансировка нагрузки
  • 37. • Балансировка на уровне инфраструктуры • Актер-роутер, работающий с пулом актеров, выбирающий «работника» согласно некому алгоритму балансировки• Балансировка на уровне планировщика/диспетчера потоков • scala.actors: fork-join pool • Akka: work-stealing dispatchers
  • 38. Актер-роутерcase class Ready(actor: class Balancer[A <: Actor](workers:Actor) Iterable[A]) extends Actor{def worker = actor{ def act = loop{ loop{ react{ react{ case msg: Ready => case msg: Ready => case msg => reply(this) val _sender = sender case msg => workers foreach {_ ! Ready(this)} //обработка react { case Ready(worker) => worker.send(msg, _sender) } } }
  • 39. +• роутер незамедлительно узнает, когда появляется незанятый работник• роутер может работать с любыми типами актеров (локальные, удаленные) -• сообщения о статусе работников создают много «шума»• роутер заблокирован, пока не освободится какой-нибудь «работник»
  • 40. Более эффективное решение в рамках однойJVM - балансировка на уровне планировщика/диспетчера потоков. AkkaПул актеров управляется work-stealing dispatcher.Если какой-то актер из пула не занят, он «крадет»сообщения из mailbox’а другого актера
  • 41. Akka: work-stealing dispatcherobject MyActor { val dispatcher = Dispatchers.newExecutorBasedEvent> DrivenWorkStealingDispatcher(name).build}class MyActor extends Actor { self.dispatcher = MyActor.dispatcher ; ...}val actor1= actorOf[MyActor].start actor2val actor2= actorOf[MyActor].start «крадет» сообщениеactor1 ! LongRunningTaskactor1 ! LongRunningTask
  • 42. Супервизор
  • 43. “If somebody dies, other peoplewill notice” Programming Erlang, Joe Armstrong
  • 44. Линки и ловушки – базовые элементы дляпостроения систем на основе актеровЛинки объединяют группу актеров в единуюподсистему. Если один из актеров «умирает»,прилинкованные актеры тоже прекращают работу actor { self link anotherActor … }Ловушка перехватывает сигнал выхода actor { self.trapExit = true … }
  • 45. Супервизор• супервизор – любой актер, прилинкованный к другому, и обрабатывающий сигнал выхода• supervisor (OTP) - если контролируемый актер умирает, перехватывает сигнал выхода, и принимает меры, в соответствии с выбранной стратегией
  • 46. Доступные реализации• Akka Supervisors• Scala-OTP – хороший выбор, если вы работаете с scala.actors
  • 47. Akka Supervisors Вдохновлены супервизорами из Erlang/OTPSupervisorConfig( OneForOneStrategy(List(classOf[Exception]), 3, 10), Supervise( myFirstActor, Стратегия поведения в Permanent) :: случае «смерти» актера Supervise( mySecondActor, Наблюдаемые актеры Permanent) :: Nil)
  • 48. • транзакционный актер• каталог актеров и ресурсов• фасад процессов• многие другие
  • 49. Спасибо за внимание! Вопросы?