Akka中的并发与响应式编程

Akka是一个构建高并发的,分布式的弹性消息驱动应用程序工具包,他支持Java和Scala。本文介绍Akka的基本功能和程序架构,特别是其中的核心概念,并用代码的形式展示如何编写一个分布式的单服务器多客户端的应用程序,。
展开查看详情

1.Advanced T opics in Concurrency and Reactive Programming: Akka Majeed Kassis

2.Become/ Unbecome Allows changing the behavior of the Actor after instantiation. “ Hot Swapping” – changing during runtime Can be done in two ways: Explicit Call It will replace the current behavior (i.e. the top of the behavior stack) No use of unbecome ! The needed behavior is explicitly installed. Behavior Stack This behavior is not the default one used in Akka ! Must ensure that the number of “pop” operations (i.e. unbecome ) matches the number of “push” ones in the long run. otherwise this amounts to a memory leak. 2

3.Initializing an Actor Initialization via constructor Done by implementing a constructor Initialization via prestart Done by overriding prestart() method Initialization via message passing Done by overriding createReceive () method 3

4.Initialization via constructor Done by implementing the actor constructor And creating a new instance using “new” prior adding it to the syste m Benefit: Allows using val fields to store any state that does not change during the life of the actor instance Drawback: The constructor is invoked for every incarnation of the actor This means child Actors will also be initialized to their original state. 4

5.Initialization via prestart Done by overwriting preStart () function. Instantiation: preStart () of an actor is only called once directly during the initialization of the first instance, that is, at creation of its ActorRef . In the case of restarts, preStart () is called from postRestart (), therefore if not overridden, preStart () is called on every incarnation. However, overriding postRestart () one can disable this behavior, and ensure that there is only one call to preStart (). One useful usage of this pattern is to disable creation of new ActorRefs for children during restarts. This can be achieved by overriding preRestart () Which means child Actors are not reset due to parent Actor restart. 5

6.Initialization via message passing Done by overwriting createReceive () function Behavior of the Actor is implemented using become() function. Benefits: Allows dynamic creation of new Actors during runtime Sometimes parameters cannot all be passed to constructor Due to it being unavailable at that time 6

7.Stopping Actors First, the actor suspends its mailbox processing and sends a stop command to all its children. Then, it keeps processing the internal termination notifications from its children until the last one is gone Finally terminating itself: I nvoking postStop () – used to clean resources on shutdown. Dumping mailbox P ublishing Terminated on the DeathWatch Telling its supervisor This ensures that actor system sub-trees terminate in an orderly fashion: Propagating the stop command to the leaves Collecting their confirmation Sending it back to the stopped supervisor If one of the actors does not respond, this whole process will be stuck! Once an Actor is stopped: New messages are sent to “ deadLetters ” mailbox of the ActorSystem . 7

8.Stopping Actor: Methods Stop: Code: actorSystemRef.stop ( anActorRef ) Shuts down an Actor immediately. PoisonPill : akka.actor.PoisonPill message can be sent to stop an Actor. The actor will stop once the message is processed. PoisonPill is enqueued as ordinary messages! It is handled after the messages already queued in the mailbox . Code : victim.tell ( akka.actor.PoisonPill.getInstance (), ActorRef.noSender ()); Graceful Stop: Allows termination or compose ordered termination of several actors. Uses Futures in order to receive a notification once the Actor has stopped. 8

9.Stopping Actor: Methods Stop: Code: actorSystemRef.stop ( anActorRef ) Shuts down an Actor immediately. PoisonPill : akka.actor.PoisonPill message can be sent to stop an Actor. The actor will stop once the message is processed. PoisonPill is enqueued as ordinary messages! It is handled after the messages already queued in the mailbox . Code : victim.tell ( akka.actor.PoisonPill.getInstance (), ActorRef.noSender ()); Graceful Stop: Allows termination or compose ordered termination of several actors. Uses Futures in order to receive a notification once the Actor has stopped. 8

10.Router’s Specially Handled Messages Broadcast Messages Message sent to router and routed automatically to all routees PoisonPill Used to stop the router Can also be used to stop all routees once owrapped by a broadcast message Kill Messages Used to kill the router so it can be stopped/resumed/restarted Management Messages Used to add/remove routes and receive information from router 10

11.Router’s Specially Handled Messages Broadcast Messages Message sent to router and routed automatically to all routees PoisonPill Used to stop the router Can also be used to stop all routees once owrapped by a broadcast message Kill Messages Used to kill the router so it can be stopped/resumed/restarted Management Messages Used to add/remove routes and receive information from router 10

12.Router’s Specially Handled Messages Broadcast Messages Message sent to router and routed automatically to all routees PoisonPill Used to stop the router Can also be used to stop all routees once owrapped by a broadcast message Kill Messages Used to kill the router so it can be stopped/resumed/restarted Management Messages Used to add/remove routes and receive information from router 10

13.Kill Messages Kill message received is handled internally by the router Can be wrapped by BroadCast message to be routed to routees . The router will throw an ActorKilledException and fail. It will then be either resumed, restarted or terminated, depending on supervision strategy. Routees that are children of the router will also be suspended, They will be affected by the supervision directive that is applied to the router. Routees that are not the routers children will not be affected . i.e. those that were created externally to the router, will not be affected . Kill Router: router.tell ( Kill.getInstance (), getTestActor ()); Kill Routees : router.tell (new Broadcast( Kill.getInstance ()), getTestActor ()); 13

14.Management Messages These messages are sent to routers. akka.routing.GetRoutees : Will make it send back its currently used routees in an akka.routing.Routees message. akka.routing.AddRoutee Will add that routee to its collection of routees . akka.routing.RemoveRoutee W ill remove that routee to its collection of routees . akka.routing.AdjustPoolSize to a pool router actor Will add or remove that number of routees to its collection of routees . 14

15.Remote Actor HelloWorld Ability to send message from client to server – remotely! Client may send two types of messages to server: Message.GREET Message.DONE Changes: Modify “ application.conf ” to support remote communication Modify Client actor to “select” Server Actor for message passing. 15

16.Modifying Server “ application.conf ” 16 akka { loglevel = INFO actor { provider = remote } remote { enabled-transports = [ " akka.remote.netty.tcp " ] netty.tcp { hostname = "127.0.0.1" port = 3553 } } }

17.Server Main 17 import akka.actor.ActorSystem ; import akka.actor.Props ; public class Main2 { public static void main(String[] args ) { //creating the system ActorSystem system = ActorSystem. create ( " HelloWorldSystem " ); //creating system actors system.actorOf ( Props. create ( Greeter. class ), "Greeter" ); } }

18.Server “Greeter” Actor 18 enum Msg implements Serializable { GREET , DONE ; } public class Greeter extends AbstractActor { @Override public Receive createReceive () { return receiveBuilder () . matchEquals ( Msg. GREET , m -> { System. out .println ( "Hello World!" ); sender().tell( Msg. DONE , self()); }) . matchEquals ( Msg. DONE , m -> { System. out .println ( "Client Disconnected!" ); }) .build(); } }

19.Modifying Client “ application.conf ” 19 akka { loglevel = INFO actor { provider = remote } remote { enabled-transports = [ " akka.remote.netty.tcp " ] netty.tcp { hostname = "127.0.0.1" port = 2552 } } }

20.Client Main 20 public class Main { public static void main(String[] args ) { akka.Main. main ( new String[] { HelloWorld. class .getName () }); } }

21.Client Remote HelloWorld 21 enum Msg implements Serializable { GREET , DONE ; } public class HelloWorld extends AbstractActor { @Override public Receive createReceive () { return receiveBuilder () . matchEquals ( Msg. DONE , m -> { // when the greeter is done, stop this actor and with it the application sender().tell( Msg. DONE , self()); getContext ().stop(self()); }) .build(); } @Override public void preStart () { // this is the first step once the Actor is added to the system. ActorSelection greeter = getContext (). actorSelection ( " akka.tcp ://HelloWorldSystem@127.0.0.1:3553/user/Greeter" ); greeter.tell ( Msg. GREET , self()); } }

22.Required Dependencies: Actor and Remote 22 These dependencies are added to the pom.xml file. They are automatically downloaded using Maven on first execution. < dependency > < groupId > com.typesafe.akka </ groupId > < artifactId > akka-actor_2.12 </ artifactId > < version >2.5.0</ version > </ dependency > < dependency > < groupId > com.typesafe.akka </ groupId > < artifactId > akka-remote_2.12 </ artifactId > < version >2.5.0</ version > </ dependency >

23.What about GUI? Simple: Text Only! What about user list in channel? Use a command to print user list Window will contain channel output You may use logging capabilities to provide output Preffered : Web UI! Play Framework: http ://www.lightbend.com/activator/template/play-akka-cluster-sample 23

24.Default Method Advantage Allows adding new functionalities to interfaces without breaking the classes that implement that interface.  Allows implementing methods directly in the interface! We add default keyword before the access modifier of the method we wish to implement. This implementation will be the default implementation for all classes implementing this interface, It can be overridden if needed. 24

25.Java8: Default Methods Implementation of isEmpty () wil act as the default implementation as long as the class does not overwrite it. If the same default method is implemented in two different interfaces, and our class extends both interfaces, we must overwrite the default method. 25 interface Stack < E > { void push ( E something ) ; E pop () ; int size () ; boolean isEmpty () ; } interface Stack < E > { void push ( E something ) ; E pop () ; int size () ; default boolean isEmpty () { return (size())==0); } }

26.Lambdas – Java8 Allows writing a method in the same place to be used. Especially useful in places where a method is being used only once, and the method definition is short. Saves the effort of declaring and writing a separate method to the containing class . Note: Lambdas implement an interface that consists of one non default function only. Syntax Example: (arg1, arg2...) -> { body } (type1 arg1, type2 arg2...) -> { body } 26

27.Code Examples 27 ( int a, int b) -> {  return a + b; }   () -> System.out.println ( "Hello World" );   (String s) -> { System.out.println (s); }   () -> 42   () -> { return 3.1415 };

28.28

29.29