为什么我的演员没有收到消息?

Why isn't my actor receiving a message?

问题:

我很难理解为什么我的 Reporter actor 没有收到基于我的 Generator actor 中的以下语句的消息:

reporter <! Message input

我的记者演员如下:

let reporterActor (mailbox:Actor<_>) =

    let rec loop() = actor { let! msg = mailbox.Receive()
                             match msg |> box :?> Command with
                             | Start     -> ()
                             | Message v -> printf "%s" v
                             | Exit      -> mailbox.Context.System.Terminate() |> ignore }
    loop() |> ignore

基本上,会启动一个接受用户输入的控制台。我的 Generator actor 将该输入转发给我的 Reporter actor。但是,上面的代码永远不会执行。

代码如下:

module Main

open System
open Akka.FSharp
open Akka.Actor
open Actors

type Command = 
    | Message of string
    | Start | Exit

let reporterActor (mailbox:Actor<_>) =

    let rec loop() = actor { let! msg = mailbox.Receive()
                             match msg |> box :?> Command with
                             | Start     -> ()
                             | Message v -> printf "%s" v
                             | Exit      -> mailbox.Context.System.Terminate() |> ignore }
    loop() |> ignore


let generatorActor (reporter:IActorRef) (mailbox:Actor<_>) message =

    let handle input = match input with
                       | "exit" -> mailbox.Context.System.Terminate |> ignore
                       | _      -> reporter <! Message input

    handle (Console.ReadLine().ToLower())

[<EntryPoint>]
let main argv = 
    let system =         System.create "system"         (Configuration.load())
    let reporterActor =  spawn system  "reporterActor"  (actorOf(reporterActor))
    let generatorActor = spawn system  "generatorActor" (actorOf2(generatorActor reporterActor))

    generatorActor <! Start
    system.AwaitTermination ()
    0

更新:

我了解到我可以通过用任意消息参数替换邮箱参数来触发我的 Reporter actor:

let reporterActor message =
     match message |> box :?> Command with
     | Start     -> ()
     | Message v -> printf "Reporting: %s" v
     | Exit      -> failwith "Kill this!"

我仍然不明白什么时候应该使用邮箱参数,什么时候应该依赖消息参数。

区别在于 actorOf 和 actorOf2 的工作方式。

actorOf 与 spawn 一起创建一个 actor 作为系统根的子级,它将使用传递给它的函数 'Message -> unit 处理消息。

actorOf2 与 spawn 结合创建一个 actor 作为您传入的 actor 的子级,该子级将使用传入的函数 'Message -> unit 处理消息。

你原来的 reporter actor 函数签名是:

Actor<'Message> -> unit

并且您使用了 spawn system "reporterActor" (actorOf(reporterActor))

在这种情况下,您是说创建的新参与者将接收的消息类型是 Actor<'Message> 类型。之所以编译,是因为 actorof 只需要一个接受 'Message 的函数,而 'Message 是通用的,因此 Actor<'Message> 满足 'Message 参数。

当您更新 reporterActor 的签名时,您将签名更改为 'Message -> unit,这是 actorOf 实际打算接受的签名。

简而言之,泛型允许您的代码编译,因为“消息并没有真正受到限制,也不应该受到限制。

发件人:http://getakka.net/docs/FSharp%20API

actorOf (fn : 'Message -> unit) (mailbox : Actor<'Message>) : Cont<'Message, 'Returned> - uses a function, which takes a message as the only parameter. Mailbox parameter is injected by spawning functions.

actorOf2 (fn : Actor<'Message> -> 'Message -> unit) (mailbox : Actor<'Message>) : Cont<'Message, 'Returned> - uses a function, which takes both the message and an Actor instance as the parameters. Mailbox parameter is injected by spawning functions. Example:

> let handleMessage (mailbox: Actor<'a>) msg =
>     match msg with
>     | Some x -> printf "%A" x
>     | None -> ()
> 
> let aref = spawn system "my-actor" (actorOf2 handleMessage) let
> blackHole = spawn system "black-hole" (actorOf (fun msg -> ()))

spawn (actorFactory : IActorRefFactory) (name : string) (f : Actor<'Message> -> Cont<'Message, 'Returned>) : IActorRef - spawns an actor using a specified actor computation expression. The actor can only be used locally.

All of these functions may be used with either the actor system or the actor itself. In the first case the spawned actor will be placed under /user root guardian of the current actor system hierarchy. In the second option the spawned actor will become a child of the actor used as the actorFactory parameter of the spawning function.