Reputation: 4730
So I have a toy example here, where I create 200 actors and then send the first 100 a "first"
message, before sending the last 100 a "second"
message.
open System
open Akka.Actor
open Akka.Configuration
open Akka.FSharp
let system = System.create "test" (Configuration.defaultConfig())
let myActor (mailbox: Actor<_>) =
actor {
let rand = System.Random()
let! message = mailbox.Receive ()
match message with
| "first" -> printfn "first group"
| _ -> printfn "second group"
Thread.SpinWait (rand.Next(100,1000))
}
let actorArray = Array.create 200 (spawn system "myActor" myActor)
{0..199} |> Seq.iter (fun a ->
actorArray.[a] <- spawn system (string a) myActor
)
// First group
{0..100} |> Seq.iter(fun a ->
actorArray.[a] <! "first"
()
)
// Second group
{101..199} |> Seq.iter(fun a ->
actorArray.[a] <! "second"
()
)
What I'd like is for the first 100 hundred actors to complete (i.e. to print and terminate) before sending messages to the second group, which does not happen.
I've started looking at Akka's F# monitoring module, but I'm not exactly sure how to implement it.
Upvotes: 1
Views: 496
Reputation: 4730
So I've created a solution, not sure if it's the most idiomatic, but it does the job!
open System
open Akka.Actor
open Akka.Configuration
open Akka.FSharp
let system = System.create "MySystem" (Configuration.defaultConfig())
let myActor (mailbox: Actor<_>) =
actor {
let rand = System.Random()
let! message = mailbox.Receive()
let sender = mailbox.Sender()
match message with
| "first" -> printfn "first group"
| _ -> printfn "second group"
Thread.SpinWait (rand.Next(100,1000))
sender <! "Done"
}
let myMonitor (mailbox: Actor<_>) =
let mutable i = 99
let actorArray = Array.create 200 (spawn system "myActor" myActor)
{0..199} |> Seq.iter (fun a ->
actorArray.[a] <- spawn system (string a) myActor
()
)
// First group
{0..100} |> Seq.iter(fun a ->
actorArray.[a] <! "first"
()
)
let rec loop() =
actor {
let! message = mailbox.Receive()
match message with
| _ ->
i <- (i - 1)
if (i = 0) then
// Second group
{101..199} |> Seq.iter(fun a ->
actorArray.[a] <! "second"
()
)
return! loop()
}
loop()
let mon = spawn system "myMon" myMonitor
In essence what happens is an external actor myMonitor
sets up the environment and begins the first set of tasks outside its recursive loop. The actors on task now send "Done"
when they complete, and this is processed inside the myMonitor
recursive loop.
Once myMonitor
has received all messages from the first block, it starts the second.
Upvotes: 1