akka - RIP Tutorial · Akka - это инструментарий с открытым...
Transcript of akka - RIP Tutorial · Akka - это инструментарий с открытым...
akka
#akka
1
1: 2
2
Examples 2
2
2: Akka HTTP 4
4
Examples 4
Akka HTTP: Hello World (Scala DSL) 4
3: DSL 5
Examples 5
DSL 5
5
5
6
6
6
4: 8
Examples 8
8
5: 11
Examples 11
11
11
6: 13
13
Examples 13
? 13
16
? 16
17
7: akka-streams 18
18
Examples 18
TwoThreeShape 18
8: Akka 20
Examples 20
Akka Streams: Hello World 20
-: 22
9: , 23
Examples 23
Akka hello world (Scala) 23
24
Akka Hello World (Java 8) 25
27
ОколоYou can share this PDF with anyone you feel could benefit from it, downloaded the latest version from: akka
It is an unofficial and free akka ebook created for educational purposes. All the content is extracted from Stack Overflow Documentation, which is written by many hardworking individuals at Stack Overflow. It is neither affiliated with Stack Overflow nor official akka.
The content is released under Creative Commons BY-SA, and the list of contributors to each chapter are provided in the credits section at the end of this book. Images may be copyright of their respective owners unless otherwise specified. All trademarks and registered trademarks are the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/ru/home 1
глава 1: Начало работы с аккой
замечания
Akka - это инструментарий с открытым исходным кодом и среда выполнения, упрощающая создание параллельных и распределенных приложений на JVM. Он реализует модель актера, известную из Erlang.
Он также должен упомянуть о любых крупных предметах в пределах акки и ссылки на связанные темы. Поскольку документация для akka является новой, вам может потребоваться создать начальные версии этих связанных тем.
Examples
Установка или настройка
Установите JDK 8 ( Windows , Linux ) и установите путь ( Windows ).1.
Установите Scala ( Linux ), для Windows посетите http://www.scala-lang.org/download/ загрузите и установите бинарный дистрибутив, установите переменную среды для scala в PATH, которая находится в \scala\bin .
2.
Установка активатора Typesafe (содержит Scala, Akka, Play, SBT) + проектные леса и шаблоны. Для быстрого запуска загрузите mini-package .
3.
Извлеките активатор Typesafe и установите PATH на activator-xxxx-minimal\bin minimum activator-xxxx-minimal\bin (он включает сценарии bash и bat для запуска активатора).
4.
Время для создания образца проекта и импорта в вашу любимую среду IDE.5.
Введите activator new в cmd / terminal.•
Вы можете выбрать 4 потому что пример Hello World основан на Scala.•
Импортируйте проект в свою любимую среду IDE и начинайте с примера Hello World .•
Готово !.•
https://riptutorial.com/ru/home 2
Скачайте akka-2.0.zip дистрибутив Akka с http://akka.io/downloads/1.
Разархивируйте akka-2.0.zip в любом каталоге. (Пример - /home/USERNAME/tools/akka-2.0) Вы хотели бы установить Akka.
2.
Установите AKKA_HOME3.
Для Linux.
# First got to the installed location cd /home/USERNAME/tools/akka-2.0 # Export the location as AKKA_HOME export AKKA_HOME=`pwd` # Check if PATH is Exported. echo $AKKA_HOME /home/USERNAME/tools/akka-2.0
4.
Для Windows
# First got to the installed location C:\USERNAME\akka> cd akka-2.0 # Set the location as AKKA_HOME C:\USERNAME\akka\akka-2.0> set AKKA_HOME=%cd% # Check if PATH is Exported. C:\USERNAME\akka\akka\akka-2.0> echo %AKKA_HOME% C:\USERNAME\akka\akka-2.0
5.
Прочитайте Начало работы с аккой онлайн: https://riptutorial.com/ru/akka/topic/2041/начало-работы-с-аккой
https://riptutorial.com/ru/home 3
глава 2: Akka HTTP
Вступление
Akka HTTP - это легкий HTTP-сервер и клиентская библиотека, использующие akka-streams
под капотом
Examples
Сервер Akka HTTP: Hello World (Scala DSL)
Следующее приложение запустит HTTP-сервер, прослушивающий порт 8080, который возвращает Hello world в GET /hello/world
import akka.actor.ActorSystem import akka.http.scaladsl.Http import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server._ import akka.stream.ActorMaterializer import scala.concurrent.Await import scala.concurrent.duration.Duration object HelloWorld extends App { implicit val system = ActorSystem("ProxySystem") implicit val mat = ActorMaterializer() val route: Route = get { path("hello" / "world") { complete("Hello world") } } val bindingFuture = Http().bindAndHandle(Route.handlerFlow(route), "127.0.0.1", port = 8080) Await.result(system.whenTerminated, Duration.Inf) }
Прочитайте Akka HTTP онлайн: https://riptutorial.com/ru/akka/topic/10108/akka-http
https://riptutorial.com/ru/home 4
глава 3: Актер DSL
Examples
Простой актер DSL
Чтобы создать простых участников без создания нового класса, вы можете использовать:
import akka.actor.ActorDSL._ import akka.actor.ActorSystem implicit val system = ActorSystem("demo") val a = actor(new Act { become { case "hello" ⇒ sender() ! "hi" } })
Контекстное переключение
Два возможных способа выдачи контекста. (Заменяя или добавляя новое поведение) предлагаются отдельно, чтобы включить беспорядочную нотацию вложенных получателей:
val a = actor(new Act { become { // this will replace the initial (empty) behavior case "info" ⇒ sender() ! "A" case "switch" ⇒ becomeStacked { // this will stack upon the "A" behavior case "info" ⇒ sender() ! "B" case "switch" ⇒ unbecome() // return to the "A" behavior } case "lobotomize" ⇒ unbecome() // OH NOES: Actor.emptyBehavior } })
Управление жизненным циклом
Крючки жизненного цикла также отображаются как элементы DSL, где последующие вызовы методов, показанных ниже, заменят содержимое соответствующих крючков:
val a = actor(new Act { whenStarting { testActor ! "started" } whenStopping { testActor ! "stopped" } })
Вышеописанное достаточно, если логический жизненный цикл актера соответствует
https://riptutorial.com/ru/home 5
циклам перезапуска (т. Е. КогдаStopping выполняется до перезапуска и когда начинается после этого). Если это нежелательно, используйте следующие два крючка:
val a = actor(new Act { become { case "die" ⇒ throw new Exception } whenFailing { case m @ (cause, msg) ⇒ testActor ! m } whenRestarted { cause ⇒ testActor ! cause } })
Вложенные актеры
Также возможно создать вложенных актеров, то есть внуков, таких как:
// here we pass in the ActorRefFactory explicitly as an example val a = actor(system, "fred")(new Act { val b = actor("barney")(new Act { whenStarting { context.parent ! ("hello from " + self.path) } }) become { case x ⇒ testActor ! x } })
надзор
Также можно назначить стратегию надзора для этих участников следующим образом:
superviseWith(OneForOneStrategy() { case e: Exception if e.getMessage == "hello" ⇒ Stop case _: Exception ⇒ Resume })
Поддержка прошивки
И последнее, но не менее важное: встроенная функция удобной магии, которая определяет, будет ли класс времени выполнения статически заданного подтипа субъекта расширять черту RequiresMessageQueue через черту Stash (это сложный способ сказать, что новый закон с Stash не работает, потому что его стираемый тип времени является просто анонимным подтипом Act). Целью является автоматическое использование соответствующего типа почтового ящика, требуемого Stash. Если вы хотите использовать эту магию, просто добавьте ActWithStash:
val a = actor(new ActWithStash { become { case 1 ⇒ stash() case 2 ⇒ testActor ! 2; unstashAll(); becomeStacked { case 1 ⇒ testActor ! 1; unbecome()
https://riptutorial.com/ru/home 6
} } })
Прочитайте Актер DSL онлайн: https://riptutorial.com/ru/akka/topic/2392/актер-dsl
https://riptutorial.com/ru/home 7
глава 4: Включение зависимостей в актера
Examples
Весенний проводник
Из-за очень специфического способа создания актера инжектирование зависимостей в экземпляр актера не является тривиальным. Чтобы вмешаться в создание экземпляра актера и позволить Spring вводить зависимости, нужно реализовать пару расширений akka. Первый из них - IndirectActorProducer :
import akka.actor.Actor; import akka.actor.IndirectActorProducer; import java.lang.reflect.Constructor; import java.util.Arrays; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; /** * An actor producer that lets Spring autowire dependencies into created actors. */ public class SpringWiredActorProducer implements IndirectActorProducer { private final ApplicationContext applicationContext; private final Class<? extends Actor> actorBeanClass; private final Object[] args; public SpringWiredActorProducer(ApplicationContext applicationContext, Class<? extends Actor> actorBeanClass, Object... args) { this.applicationContext = applicationContext; this.actorBeanClass = actorBeanClass; this.args = args; } @Override public Actor produce() { Class[] argsTypes = new Class[args.length]; for (int i = 0; i < args.length; i++) { if (args[i] == null) { argsTypes[i] = null; } else { argsTypes[i] = args[i].getClass(); } } Actor result = null; try { if (args.length == 0) { result = (Actor) actorBeanClass.newInstance(); } else { try { result = (Actor) actorBeanClass.getConstructor(argsTypes).newInstance(args); } catch (NoSuchMethodException ex) { // if types of constructor don't match exactly, try to find appropriate
https://riptutorial.com/ru/home 8
constructor for (Constructor<?> c : actorBeanClass.getConstructors()) { if (c.getParameterCount() == args.length) { boolean match = true; for (int i = 0; match && i < argsTypes.length; i++) { if (argsTypes[i] != null) { match = c.getParameters()[i].getType().isAssignableFrom(argsTypes[i]); } } if (match) { result = (Actor) c.newInstance(args); break; } } } } } if (result == null) { throw new RuntimeException(String.format("Cannot find appropriate constructor for %s and types (%s)", actorBeanClass.getName(), Arrays.toString(argsTypes))); } else { applicationContext.getAutowireCapableBeanFactory().autowireBeanProperties(result, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true); } } catch (ReflectiveOperationException e) { throw new RuntimeException("Cannot instantiate an action of class " + actorBeanClass.getName(), e); } return result; } @Override public Class<? extends Actor> actorClass() { return (Class<? extends Actor>) actorBeanClass; } }
Этот продюсер создает экземпляр актера и вводит зависимости перед возвратом экземпляра актера.
Мы можем подготовить Props для создания актера с помощью SpringWiredActorProducer следующим образом:
Props.create(SpringWiredActorProducer.class, applicationContext, actorBeanClass, args);
Однако было бы лучше обернуть этот призыв следующей весенней фасолью:
import akka.actor.Extension; import akka.actor.Props; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component;
https://riptutorial.com/ru/home 9
/** * An Akka Extension to inject dependencies to {@link akka.actor.Actor}s with * Spring. */ @Component public class SpringProps implements Extension, ApplicationContextAware { private volatile ApplicationContext applicationContext; /** * Creates a Props for the specified actorBeanName using the * {@link SpringWiredActorProducer}. * * @param actorBeanClass The class of the actor bean to create Props for * @param args arguments of the actor's constructor * @return a Props that will create the named actor bean using Spring */ public Props create(Class actorBeanClass, Object... args) { return Props.create(SpringWiredActorProducer.class, applicationContext, actorBeanClass, args); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
Вы можете автоматически создавать SpringProps везде, где актер создается (даже в самом актере) и создавать пружинные актеры следующим образом:
@Autowired private SpringProps springProps; //... actorSystem.actorOf(springProps.create(ActorClass.class), actorName); //or inside an actor context().actorOf(springProps.create(ActorClass.class), actorName);
Предполагая, что ActorClass расширяет UntypedActor и имеет свойства, аннотированные с помощью @Autowired , эти зависимости будут введены сразу после создания экземпляра.
Прочитайте Включение зависимостей в актера онлайн: https://riptutorial.com/ru/akka/topic/4717/включение-зависимостей-в-актера
https://riptutorial.com/ru/home 10
глава 5: диспетчеры
Examples
Диспетчер по умолчанию
Акка MessageDispatcher - это то, что делает Акка Актеры «тикают», это двигатель машины, так сказать. Все реализации MessageDispatcher также являются ExecutionContext, а это означает, что они могут использоваться для выполнения произвольного кода, например Futures.
Каждая система ActorSystem будет иметь диспетчер по умолчанию, который будет использоваться в случае, если для актера не настроено ничего другого. Диспетчер по умолчанию может быть настроен и по умолчанию является Dispatcher с указанным default-executor . Если создается ActorSystem с переданным ExecutionContext , этот ExecutionContext
будет использоваться как исполнитель по умолчанию для всех диспетчеров в этой ActorSystem. Если не указан ExecutionContext, он будет akka.actor.default-dispatcher.default-executor.fallback исполнителю, указанному в akka.actor.default-dispatcher.default-executor.fallback . По умолчанию это fork-join-executor , который дает отличную производительность в большинстве случаев.
Настройка диспетчера для актера
Поэтому, если вы хотите, чтобы ваш Актер был другим диспетчером, чем по умолчанию, вам нужно сделать две вещи, из которых первая заключается в настройке диспетчера в вашем application.conf :
my-dispatcher { # Dispatcher is the name of the event-based dispatcher type = Dispatcher # What kind of ExecutionService to use executor = "fork-join-executor" # Configuration for the fork join pool fork-join-executor { # Min number of threads to cap factor-based parallelism number to parallelism-min = 2 # Parallelism (threads) ... ceil(available processors * factor) parallelism-factor = 2.0 # Max number of threads to cap factor-based parallelism number to parallelism-max = 10 } # Throughput defines the maximum number of messages to be # processed per actor before the thread jumps to the next actor. # Set to 1 for as fair as possible. throughput = 100 }
И вот еще один пример, который использует «thread-pool-executor»:
https://riptutorial.com/ru/home 11
my-thread-pool-dispatcher { # Dispatcher is the name of the event-based dispatcher type = Dispatcher # What kind of ExecutionService to use executor = "thread-pool-executor" # Configuration for the thread pool thread-pool-executor { # minimum number of threads to cap factor-based core number to core-pool-size-min = 2 # No of core threads ... ceil(available processors * factor) core-pool-size-factor = 2.0 # maximum number of threads to cap factor-based number to core-pool-size-max = 10 } # Throughput defines the maximum number of messages to be # processed per actor before the thread jumps to the next actor. # Set to 1 for as fair as possible. throughput = 100 }
Затем вы можете определить диспетчера, который будет использоваться для вашего актера внутри вашей конфигурации, например
akka.actor.deployment { /myactor { dispatcher = my-dispatcher } }
и создайте этого актера с именем, указанным в config:
import akka.actor.Props val myActor = context.actorOf(Props[MyActor], "myactor")
Или вы можете найти своего диспетчера с помощью:
import akka.actor.Props val myActor = context.actorOf(Props[MyActor].withDispatcher("my-dispatcher"), "myactor1")
Прочитайте диспетчеры онлайн: https://riptutorial.com/ru/akka/topic/3228/диспетчеры
https://riptutorial.com/ru/home 12
глава 6: Надзор и мониторинг в Акке
замечания
Ссылки: akka.io/docs
Просмотрите мой блог: https://blog.knoldus.com/2016/08/07/supervision-and-monitoring-in-akka/
Examples
Что такое надзор?
Описывает зависимость между участниками, родительским и дочерним образованием. Родитель является уникальным, потому что он создал дочернего актера, поэтому родитель отвечает за реакцию, когда в его ребенке происходят сбои.
И родитель решает, какой выбор нужно выбрать. Когда родитель получает сигнал отказа от своего потомка, тогда в зависимости от характера сбоя родитель решает следующие варианты:
Резюме. Родитель начинает воспроизведение дочернего актера, сохраняя его внутреннее состояние.
Перезапуск: родитель запускает дочернего актера, очищая его внутреннее состояние.
Остановить: остановить ребенка навсегда.
Эскалация: эскалация сбоя путем отказа от себя и распространения отказа его родителям.
https://riptutorial.com/ru/home 13
Жизненный цикл Akka
Всегда важно просмотреть часть иерархии надзора, которая объясняет вариант эскалации. Каждый руководитель должен покрывать все возможные случаи сбоя.
https://riptutorial.com/ru/home 14
Система исполнителей: Источник: doc.akka.io
/ пользователь: Актер пользователя Guardian
Актер, созданный с использованием system.actorOf (), является дочерним элементом пользователя-опекуна. Всякий раз, когда опекун пользователя завершается, все созданные пользователем участники также будут прерваны. Пользователь, созданный пользователем верхнего уровня, определяется персонажем-хранителем, как они будут контролироваться. Root Guardian - супервизор пользователя-хранителя.
/ root: Корневой хранитель
Коренный опекун-актер является отцом всей системы актеров. Он контролирует актера-опекуна и системного опекуна-актера.
https://riptutorial.com/ru/home 15
Стратегии надзора
Существует два типа стратегий надзора, которыми мы следуем, чтобы контролировать любого актера:
Стратегия «один-к-одному»1.
Стратегия «один для всех»2.
case object ResumeException extends Exception case object StopException extends Exception case object RestartException extends Exception override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 1 second){ case ResumeException => Resume case RestartException => Restart case StopException => Stop case _: Exception => Escalate }
Что такое мониторинг?
Мониторинг жизненного цикла в Акке обычно называется DeathWatch.
Мониторинг, таким образом, используется для привязки одного актора к другому, чтобы он мог реагировать на прекращение действия другого участника, в отличие от наблюдения, которое реагирует на отказ.
https://riptutorial.com/ru/home 16
мониторинг
Мониторинг особенно полезен, если супервизор не может просто перезапустить свои дети и должен их прекратить, например, в случае ошибок во время инициализации актера. В этом случае он должен следить за этими детьми и воссоздавать их или планировать себя, чтобы повторить это позже.
Репозиторий кода
Наблюдение и мониторинг
Прочитайте Надзор и мониторинг в Акке онлайн: https://riptutorial.com/ru/akka/topic/7831/
надзор-и-мониторинг-в-акке
https://riptutorial.com/ru/home 17
глава 7: Пользовательские формы akka-streams
замечания
akka предоставляет некоторые предопределенные формы, которые, вероятно, должны соответствовать 99,9% вашего использования. создание новой формы должно выполняться только в очень редких случаях. предопределенные формы:
Source - 1 розетка, нет входов•
Sink - 1 вход, без розетки•
Flow - 1 вход, 1 выход•
BidiFlow - 2 входа, 2 выхода•
Closed - нет входов, нет выходов•
FanInN - N ( N <= 22), 1 выход•
FanOutN - N ( N <= 22), 1 вход•
UniformFanIn - любое количество входов одного и того же типа, 1 выход•
UniformFanOut - любое количество выходов одного типа, 1 вход•
Amorphous - любое количество входов или выходов, но нетипизированное.•
Examples
TwoThreeShape
простой пример того, как определить пользовательскую форму с двумя входами и тремя выходами.
case class TwoThreeShape[-In1, -In2, +Out1, +Out2, +Out3]( in1: Inlet[In1@uncheckedVariance], in2: Inlet[In2@uncheckedVariance], out1: Outlet[Out1@uncheckedVariance], out2: Outlet[Out2@uncheckedVariance], out3: Outlet[Out3@uncheckedVariance]) extends Shape { override val inlets: immutable.Seq[Inlet[_]] = List(in1, in2) override val outlets: immutable.Seq[Outlet[_]] = List(out1, out2, out3) override def deepCopy(): TwoThreeShape[In1, In2, Out1, Out2, Out3] = TwoThreeShape(in1.carbonCopy(), in2.carbonCopy(), out1.carbonCopy(), out2.carbonCopy(), out3.carbonCopy()) override def copyFromPorts(inlets: immutable.Seq[Inlet[_]], outlets: immutable.Seq[Outlet[_]]): Shape = {
https://riptutorial.com/ru/home 18
require(inlets.size == 2, s"proposed inlets [${inlets.mkString(", ")}] do not fit TwoThreeShape") require(outlets.size == 3, s"proposed outlets [${outlets.mkString(", ")}] do not fit TwoThreeShape") TwoThreeShape(inlets(0), inlets(1), outlets(0), outlets(1), outlets(2)) } }
пример использования для этой странной формы: этап, который пройдет через элементы из 2 потоков, сохраняя при этом соотношение количества элементов, переданных в потоках:
def ratioCount[X,Y]: Graph[TwoThreeShape[X,Y,X,Y,(Int,Int)],NotUsed] = { GraphDSL.create() { implicit b => import GraphDSL.Implicits._ val x = b.add(Broadcast[X](2)) val y = b.add(Broadcast[Y](2)) val z = b.add(Zip[Int,Int]) x.out(1).conflateWithSeed(_ => 1)((count,_) => count + 1) ~> z.in0 y.out(1).conflateWithSeed(_ => 1)((count,_) => count + 1) ~> z.in1 TwoThreeShape(x.in,y.in,x.out(0),y.out(0),z.out) } }
Прочитайте Пользовательские формы akka-streams онлайн: https://riptutorial.com/ru/akka/topic/3282/пользовательские-формы-akka-streams
https://riptutorial.com/ru/home 19
глава 8: Потоки Akka
Examples
Akka Streams: Hello World
Akka Streams позволяет вам легко создавать поток, используя возможности инфраструктуры Akka без явного определения поведения и сообщений актера. Каждый поток будет иметь по крайней мере один Source (источник данных) и по крайней мере один Sink (назначение данных).
import akka.actor.ActorSystem import akka.stream.ActorMaterializer import akka.stream.scaladsl.{Sink, Source} import java.io.File val stream = Source(Seq("test1.txt", "test2.txt", "test3.txt")) .map(new File(_)) .filter(_.exists()) .filter(_.length() != 0) .to(Sink.foreach(f => println(s"Absolute path: ${f.getAbsolutePath}")))
В этом кратком примере у нас есть Seq имен файлов, которые мы вводим в поток. Сначала мы сопоставляем их с File , затем отфильтровываем файлы, которые не существуют, а затем файлы, длина которых равна 0. Если файл прошел через фильтры, он печатается в stdout .
Потоки Akka также позволяют создавать потоки модульным способом. Вы можете создать Flow с частичными модулями вашего потока. Если мы возьмем тот же пример, мы могли бы также сделать:
import akka.actor.ActorSystem import akka.stream.ActorMaterializer import akka.stream.scaladsl.{Sink, Source} import java.io.File implicit val actorSystem = ActorSystem("system") implicit val actorMaterializer = ActorMaterializer() val source = Source(List("test1.txt", "test2.txt", "test3.txt")) val mapper = Flow[String].map(new File(_)) val existsFilter = Flow[File].filter(_.exists()) val lengthZeroFilter = Flow[File].filter(_.length() != 0) val sink = Sink.foreach[File](f => println(s"Absolute path: ${f.getAbsolutePath}")) val stream = source .via(mapper) .via(existsFilter) .via(lengthZeroFilter) .to(sink)
https://riptutorial.com/ru/home 20
stream.run()
Во второй версии мы можем видеть , что mapper , existsFilter , lengthZeroFilter являются Flow s. Вы можете создать их в потоке, используя метод via . Эта возможность позволит вам повторно использовать фрагменты кода. Важно отметить, что Flow может быть апатридом или состоянием. В случае состояния состояния вы должны быть осторожны при повторном использовании.
Вы также можете думать о потоках как о Graphs . Akka Streams также предоставляет мощный GraphDSL для GraphDSL определения сложных потоков. Следуя тому же примеру, мы могли бы сделать:
import java.io.File import akka.actor.ActorSystem import akka.stream.{ActorMaterializer, ClosedShape} import akka.stream.scaladsl.{Flow, GraphDSL, RunnableGraph, Sink, Source} implicit val actorSystem = ActorSystem("system") implicit val actorMaterializer = ActorMaterializer() val graph = RunnableGraph.fromGraph(GraphDSL.create() { implicit b => import GraphDSL.Implicits._ val source = Source(List("test1.txt", "test2.txt", "test3.txt")) val mapper = Flow[String].map(new File(_)) val existsFilter = Flow[File].filter(_.exists()) val lengthZeroFilter = Flow[File].filter(_.length() != 0) val sink = Sink.foreach[File](f => println(s"Absolute path: ${f.getAbsolutePath}")) source ~> mapper ~> existsFilter ~> lengthZeroFilter ~> sink ClosedShape }) graph.run()
Также возможно создать агрегированный поток, используя GraphDSL . Например, если мы хотим объединить картограф и два фильтра в одном, что мы могли бы сделать:
val combinedFlow = Flow.fromGraph(GraphDSL.create() { implicit builder => import GraphDSL.Implicits._ val mapper = builder.add(Flow[String].map(new File(_))) val existsFilter = builder.add(Flow[File].filter(_.exists())) val lengthZeroFilter = builder.add(Flow[File].filter(_.length() != 0)) mapper ~> existsFilter ~> lengthZeroFilter FlowShape(mapper.in, lengthZeroFilter.out) })
И затем используйте его как отдельный блок. combinedFlow FlowShape будет FlowShape или PartialGraph . Мы можем, например, с via :
https://riptutorial.com/ru/home 21
val stream = source .via(combinedFlow) .to(sink) stream.run()
Или используя GraphDSL :
val graph = RunnableGraph.fromGraph(GraphDSL.create() { implicit b => import GraphDSL.Implicits._ val source = Source(List("test1.txt", "test2.txt", "test3.txt")) val sink = Sink.foreach[File](f => println(s"Absolute path: ${f.getAbsolutePath}")) source ~> combinedFlow ~> sink ClosedShape }) graph.run()
Акка-потоки: субпотоки
Вы можете динамически разветвлять поток в нескольких подпотоках с помощью groupBy . Продолжающиеся этапы применяются к каждому подпотоку, пока вы не объедините их обратно с помощью mergeSubstreams .
val sumByKey: Flow[(String, Int), Int, NotUsed] = Flow[(String, Int)]. groupBy(Int.maxValue, _._1). //forks the flow map(_._2). //this is applied to each subflow fold(0)(_ + _). mergeSubstreams //the subflow outputs are merged back together
Прочитайте Потоки Akka онлайн: https://riptutorial.com/ru/akka/topic/7394/потоки-akka
https://riptutorial.com/ru/home 22
глава 9: Привет, мир
Examples
Akka hello world (Scala)
Добавить зависимость akka-actor (пример SBT)1.
libraryDependencies += "com.typesafe.akka" % "akka-actor_2.11" % "2.4.8"
Создание классов актеров:2.
Актер для вывода строки:
class OutputActor extends Actor { override def receive: Receive = { case message => println(message) } }
Актер для модификации строки:
class AppendActor(outputActor: ActorRef) extends Actor { override def receive: Receive = { case message: String => val changed = s"Hello, $message!" outputActor ! changed case unknown => println(s"unknown message: $unknown") } }
Создавать актерские системы и отправлять сообщения3.
object HelloWorld extends App { val system = ActorSystem("HelloWorld") val outputActor = system.actorOf(Props[OutputActor], name = "output") val appendActor = system.actorOf(Props(classOf[AppendActor], outputActor), name = "appender") appendActor ! "Akka" // send test message Thread.sleep(500) // wait for async evaluation system.terminate() // terminate actors system }
Выход программы:
Привет, Акка!
https://riptutorial.com/ru/home 23
Простая актерская реализация
Рассмотрите связь между Сотрудником и его отделом кадров.
В широком смысле это объясняется в следующих шести шагах, когда сообщение передается актеру:
Сотрудник создает что-то, называемое ActorSystem .1.
https://riptutorial.com/ru/home 24
Он использует ActorSystem для создания чего-то, называемого ActorRef . Сообщение (MSG) отправляется в ActorRef (прокси-сервер для ActorRef HR).
2.
Актер ref передает сообщение вместе с Message Dispatcher .3.
Грузоотправитель ставит в очередь сообщения в целевом Актере MailBox .4.
Затем Диспетчер помещает Mailbox в поток (подробнее об этом в следующем разделе).5.
MailBox удаляет сообщение и, в конечном итоге, делегирует его фактическому методу receive персонажа.
6.
/** The Main Program consider it as a Employee Actor that is sending the requests **/ object EmployeeActorApp extends App{ //Initialize the ActorSystem val actorSystem=ActorSystem("HrMessageingSystem") //construct the HR Actor Ref val hrActorRef=actorSystem.actorOf(Props[HrActor]) //send a message to the HR Actor hrActorRef!Message //Let's wait for a couple of seconds before we shut down the system Thread.sleep (2000) //Shut down the ActorSystem. actorSystem.shutdown() } /** The HRActor reads the message sent to it and performs action based on the message Type **/ class HRActor extends Actor { def receive = { case s: String if(s.equalsIgnoreCase(“SICK”)) => println("Sick Leave applied”) case s: String if(s.equalsIgnoreCase(“PTO”)) => println("PTO applied “) }
}
Akka Hello World (Java 8)
Добавьте эту зависимость в свой проект POM:
<dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-actor_2.11</artifactId> <version>2.4.4</version> </dependency>
Создать актер
https://riptutorial.com/ru/home 25
public class HelloWorldActor extends AbstractActor { public HelloActor() { receive(ReceiveBuilder .match(SayHello.class, this::sayHello) .match(SayBye.class, this::sayBye) .build()); } private void sayHello(final SayHello message) { System.out.println("Hello World"); } private void sayHello(final SayBye message) { System.out.println("Bye World"); } public static Props props() { return Props.create(HelloWorldActor.class); } }
Создайте тест Junit для актера
public class HelloActorTest { private ActorSystem actorSystem; @org.junit.Before public void setUp() throws Exception { actorSystem = ActorSystem.create(); } @After public void tearDown() throws Exception { JavaTestKit.shutdownActorSystem(actorSystem); } @Test public void testSayHello() throws Exception { new JavaTestKit(actorSystem) { { ActorRef helloActorRef = actorSystem.actorOf(HelloWorldActor.props()); helloActorRef.tell(new SayHello(), ActorRef.noSender()); helloActorRef.tell(new SayBye(), ActorRef.noSender()); } }; } }
Прочитайте Привет, мир онлайн: https://riptutorial.com/ru/akka/topic/3283/привет--мир
https://riptutorial.com/ru/home 26
кредиты
S. No
Главы Contributors
1Начало работы с аккой
12Sandy, Community, noelyahan
2 Akka HTTP Cyrille Corpet, Konrad 'ktoso' Malawski
3 Актер DSL Martin Seeler
4Включение зависимостей в актера
Oleg Kurbatov
5 диспетчеры Martin Seeler
6Надзор и мониторинг в Акке
Prabhat Kashyap
7Пользовательские формы akka-streams
gilad hoch
8 Потоки Akka Cyrille Corpet, hveiga
9 Привет, мир12Sandy, Cortwave, Fabien Benoit-Koch, Konrad 'ktoso' Malawski, tmbo
https://riptutorial.com/ru/home 27