如何使用F#实现Props.Create

时间:2017-03-23 16:43:55

标签: f# akka.net akka.net-cluster

我尝试将正在运行的C#示例移植到OOP version of F#

远程演员(在单独的进程中)没有收到消息。

我收到以下错误:

[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://system2@localhost:8080] <- akka.
tcp://system1@localhost: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)

以下是正在使用的C#版本:

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();
}

这是使用OOP到F#的端口:

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

问题:

我是否想在调用 Props.Create 方法时将 SomeActor 向上转换为对象类型?

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

上面的代码是我所知道的唯一区别。

唯一的另一个区别是tcp路径。

C#的TCP:

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

F#的TCP:

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

1 个答案:

答案 0 :(得分:3)

Props对象是目标actor创建过程的描述符。此外,它必须是可序列化的,因为有时它可能包含在通过网络传递的消息中。

为了以这种方式工作,Props在内部以(actor-type,actor-constructor-arguments)的形式描述了actor构造。 Props.Create(() => new Actor())只是这里的一个帮助:它实际上做的是将构造函数表达式解构为带参数的类型信息。这就是它仅适用于new Actor()表达式的原因。

你的F#代码的问题在于你将actor创建定义为F#函数,其中道具解构器不知道如何处理。您可能仍希望使用以下方式创建演员:

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

但是你需要自己保持构造函数params的正确性。您也可以使用它与typed version of props进行Akkling。