2017-03-23 1 views
1

J'ai essayé de porter un échantillon de travail de C# à un OOP version of F#.Comment implémenter Props.Create using F #

Les acteurs distants (sur un processus séparé) ne reçoivent pas de messages.

Je reçois l'erreur suivante:

[ERROR][3/23/2017 4:39:10 PM][Thread 0008][[akka://system2/system/endpointManage 
r/reliableEndpointWriter-akka.tcp%3A%2F%2Fsystem1%40localhost%3A8090-1/endpointW 
riter#1919547364]] AssociationError [akka.tcp://[email protected]:8080] <- akka. 
tcp://[email protected]:8090: Error [Object reference not set to an instance of 
an object.] [ at Akka.Serialization.Serialization.FindSerializerForType(Type o 
bjectType) 
    at Akka.Remote.Serialization.DaemonMsgCreateSerializer.GetArgs(DaemonMsgCreat 
eData proto) 
    at Akka.Remote.Serialization.DaemonMsgCreateSerializer.FromBinary(Byte[] byte 
s, Type type) 
    at Akka.Serialization.Serialization.Deserialize(Byte[] bytes, Int32 serialize 
rId, String manifest) 

est ici la version C# de travail:

using (var system = ActorSystem.Create("system1", config)) 
{ 
    var reply = system.ActorOf<ReplyActor>("reply"); 

    //create a remote deployed actor 
    var remote1 = system.ActorOf(Props.Create(() => new SomeActor()).WithRouter(FromConfig.Instance), "remoteactor1"); 
    var remote2 = system.ActorOf(Props.Create(() => new SomeActor()).WithRouter(FromConfig.Instance), "remoteactor2"); 
    var remote3 = system.ActorOf(Props.Create(() => new SomeActor()).WithRouter(FromConfig.Instance), "remoteactor3"); 

    var hashGroup = system.ActorOf(Props.Empty.WithRouter(new ConsistentHashingGroup(config))); 

    Task.Delay(500).Wait(); 

    var routee1 = Routee.FromActorRef(remote1); 
    hashGroup.Tell(new AddRoutee(routee1)); 

    var routee2 = Routee.FromActorRef(remote2); 
    hashGroup.Tell(new AddRoutee(routee2)); 

    var routee3 = Routee.FromActorRef(remote3); 
    hashGroup.Tell(new AddRoutee(routee3)); 

    Task.Delay(500).Wait(); 

    for (var i = 0; i < 5; i++) 
    { 
     for (var j = 0; j < 7; j++) 
     { 
      var message = new SomeMessage(j, $"remote message: {j}"); 
      hashGroup.Tell(message, reply); 
     } 
    } 

    Console.ReadLine(); 
} 

Voici le port à F # en utilisant OOP:

use system = ActorSystem.Create("system1", config) 
let reply = system.ActorOf<ReplyActor>("reply") 

let props1 = Props.Create(fun() -> SomeActor() :> obj) 
let props2 = Props.Create(fun() -> SomeActor() :> obj) 
let props3 = Props.Create(fun() -> SomeActor() :> obj) 

let remote1 = system.ActorOf(props1.WithRouter(FromConfig.Instance), "remoteactor1") 
let remote2 = system.ActorOf(props2.WithRouter(FromConfig.Instance), "remoteactor2") 
let remote3 = system.ActorOf(props3.WithRouter(FromConfig.Instance), "remoteactor3") 

let hashGroup = system.ActorOf(Props.Empty.WithRouter(ConsistentHashingGroup(config))) 
Task.Delay(500).Wait(); 

let routee1 = Routee.FromActorRef(remote1); 
hashGroup.Tell(new AddRoutee(routee1)); 

let routee2 = Routee.FromActorRef(remote2); 
hashGroup.Tell(new AddRoutee(routee2)); 

let routee3 = Routee.FromActorRef(remote3); 
hashGroup.Tell(new AddRoutee(routee3)); 

Task.Delay(500).Wait(); 

for i = 0 to 5 do 
    for j = 0 to 7 do 

     let message = new HashMessage(j, sprintf "remote message: %i" j); 
     hashGroup.Tell(message, reply); 

Console.ReadLine() |> ignore 

Question:

Suis-je supposé transtyper SomeActor au type d'objet lors de l'appel de la méthode Props.Create?

let props1 = Props.Create(fun() -> SomeActor() :> obj) 
let props2 = Props.Create(fun() -> SomeActor() :> obj) 
let props3 = Props.Create(fun() -> SomeActor() :> obj) 

Le code ci-dessus est la seule différence que je connais.

La seule autre différence est le chemin tcp.

C# 's TCP:

remote { 
    dot-netty.tcp { 
     port = 8090 
     hostname = localhost 
    } 

F #' s TCP:

remote { 
     helios.tcp { 
      port = 8090 
      hostname = localhost 
     } 
+2

Vous ne savez pas si c'est une différence matérielle, mais vos boucles for sont 1 élément plus grand dans F # (puisque vous vérifiez pour <<'plutôt que <=' en C#). – kvb

+0

Merci pour cette observation kvb. –

+0

Que se passe-t-il si vous ne migrez pas vers obj? On dirait qu'il y a un tas de substitutions de 'Create', donc je ne serais pas surpris si les upcast en forçaient un différent, ce qui pourrait expliquer les résultats. – kvb

Répondre

3

objet Props est un descripteur pour le processus de création de l'acteur cible. En outre, il doit être sérialisable, car il peut parfois être inclus dans les messages transmis via le réseau. Pour fonctionner de cette façon, Props décrit en interne la construction de l'acteur sous la forme de (type acteur, argument-constructeur-argument). Props.Create(() => new Actor()) est seulement un assistant ici: ce qu'il fait réellement, est de déconstruire l'expression du constructeur en type info avec des arguments. C'est pourquoi cela ne fonctionne qu'avec les expressions new Actor(). Le problème avec votre code F # est que vous définissez la création d'acteur comme une fonction F #, que les accessoires déconstructeurs ne savent pas comment gérer. Vous pouvez quand même créer vos acteurs en utilisant:

Props.Create(typeof<Actor>, [| arg1; arg2 |]) 

mais vous devez garder l'exactitude du constructeur params par vous-même. Vous pouvez également utiliser, par exemple, Akkling avec typed version of props.