ℹ️ Select 'Choose Exercise', or randomize 'Next Random Exercise' in selected language.

Choose Exercise:
Timer 00:00
WPM --
Score --
Acc --
Correct chars --

F# Actor Concurrency: Simple Message Passing

F#

Goal -- WPM

Ready
Exercise Algorithm Area
1(*@
2Defines the messages that actors can send to each other.
3*@)
4type GreetingMessage =
5| Greet of sender: IActorRef
6| Greeting of message: string
7
8(*@
9The Greeter actor.
10It receives a reference to the Responder actor and sends it a Greet message.
11*@)
12type GreeterActor(responder: IActorRef) =
13inherit Actor()
14
15// Override the receive method to handle incoming messages
16override this.Receive(message) =
17match message with
18| :? string as str ->
19printfn "Greeter received a command: %s"
20// Send a Greet message to the responder actor
21responder <! Greet(sender = this.Self) // 'this.Self' is a reference to the current actor
22| _ ->
23printfn "Greeter received an unknown message type."
24
25(*@
26The Responder actor.
27It receives Greet messages and sends back a Greeting message.
28*@)
29type ResponderActor() =
30inherit Actor()
31
32// Override the receive method to handle incoming messages
33override this.Receive(message) =
34match message with
35| :? Greet as greetMsg ->
36printfn "Responder received Greet message from %s"
37// Send a Greeting message back to the sender
38greetMsg.sender <! Greeting(message = "Hello from Responder!")
39| :? Greeting as greetingMsg ->
40printfn "Responder received final Greeting: %s"
41| _ ->
42printfn "Responder received an unknown message type."
43
44(*@
45Sets up and runs the actor system.
46*@)
47let runActorSystem () =
48// Create an actor system
49let system = ActorSystem.Create("MyActorSystem")
50
51// Create the Responder actor
52let responder = system.ActorOf<ResponderActor>()
53
54// Create the Greeter actor, passing the Responder's reference
55let greeter = system.ActorOf(fun () -> GreeterActor(responder))
56
57// Send an initial command to the Greeter actor to start the process
58greeter <! "Start"
59
60// Keep the system running for a bit to allow messages to process
61System.Threading.Thread.Sleep(2000) // Sleep for 2 seconds
62
63// Shutdown the actor system
64system.Terminate() |> ignore
65
66(*@
67A variation of the Greeter actor that sends a different message.
68*@)
69type AnotherGreeterActor(responder: IActorRef) =
70inherit Actor()
71
72override this.Receive(message) =
73match message with
74| :? string as str ->
75printfn "AnotherGreeter received command: %s"
76responder <! "Hello there!"
77| _ ->
78printfn "AnotherGreeter received unknown message."
79
80(*@
81A variation of the Responder actor that handles a string message.
82*@)
83type StringResponderActor() =
84inherit Actor()
85
86override this.Receive(message) =
87match message with
88| :? string as str ->
89printfn "StringResponder received: %s"
90| _ ->
91printfn "StringResponder received unknown message."
92
93(*@
94Demonstrates the interaction between AnotherGreeterActor and StringResponderActor.
95*@)
96let runAnotherActorSystem () =
97let system = ActorSystem.Create("AnotherActorSystem")
98let responder = system.ActorOf<StringResponderActor>()
99let greeter = system.ActorOf(fun () -> AnotherGreeterActor(responder))
100greeter <! "Initiate"
101System.Threading.Thread.Sleep(1000)
102system.Terminate() |> ignore
103
104(*@
105A simple actor that just prints its received message.
106*@)
107type PrinterActor() =
108inherit Actor()
109
110override this.Receive(message) =
111printfn "PrinterActor received: %A"
112
113(*@
114Demonstrates sending a message to a PrinterActor.
115*@)
116let runPrinterSystem () =
117let system = ActorSystem.Create("PrinterSystem")
118let printer = system.ActorOf<PrinterActor>()
119printer <! "This is a test message."
120System.Threading.Thread.Sleep(500)
121system.Terminate() |> ignore
122
123(*@
124A more complex message structure.
125*@)
126type ComplexMessage = {
127Content: string;
128From: IActorRef;
129}
130
131(*@
132An actor that handles ComplexMessage.
133*@)
134type ComplexMessageHandlerActor() =
135inherit Actor()
136
137override this.Receive(message) =
138match message with
139| :? ComplexMessage as msg ->
140printfn "ComplexMessageHandler received '%s' from %s"
141msg.From <! "Acknowledged"
142| _ ->
143printfn "ComplexMessageHandler received unknown message."
144
145(*@
146Demonstrates the ComplexMessageHandlerActor.
147*@)
148let runComplexMessageSystem () =
149let system = ActorSystem.Create("ComplexMessageSystem")
150let handler = system.ActorOf<ComplexMessageHandlerActor>()
151handler <! ComplexMessage(Content = "Important Data", From = handler) // Sending to self for demo
152System.Threading.Thread.Sleep(1000)
153system.Terminate() |> ignore
154
155(*@
156Final actor system setup.
157*@)
158let finalActorSystemSetup () =
159let system = ActorSystem.Create("FinalActorSystem")
160let responder = system.ActorOf<ResponderActor>()
161let greeter = system.ActorOf(fun () -> GreeterActor(responder))
162greeter <! "Go"
163System.Threading.Thread.Sleep(1500)
164system.Terminate() |> ignore
Algorithm description viewbox

F# Actor Concurrency: Simple Message Passing

Algorithm description:

This F# code demonstrates a basic actor system using a conceptual actor framework (like Akka.NET). It defines two actors: `GreeterActor` and `ResponderActor`. The `GreeterActor` initiates a conversation by sending a `Greet` message to the `ResponderActor`, which then replies with a `Greeting` message. This showcases asynchronous message passing and actor communication, fundamental concepts in concurrent programming.

Algorithm explanation:

The actor system is built around the concept of actors communicating via asynchronous messages. The `GreeterActor` and `ResponderActor` inherit from a base `Actor` class and override the `Receive` method to handle incoming messages. When the `GreeterActor` receives a string command, it sends a `Greet` message (containing a reference to itself, `this.Self`) to the `ResponderActor`. The `ResponderActor`, upon receiving `Greet`, sends a `Greeting` message back to the original sender. The `ActorSystem` manages the lifecycle of these actors. The time complexity is difficult to define precisely for message passing as it's asynchronous and depends on the scheduler, but processing a single message by an actor is typically O(1) for the `Receive` method itself, excluding the work done by the message handler. Space complexity is O(M) where M is the number of messages in the mailbox. Edge cases include unknown message types, which are handled by a default case in the `Receive` method. The system works by decoupling actors, allowing them to operate concurrently without direct method calls, relying solely on message queues.

Pseudocode:

define message types: Greet(sender), Greeting(message)

actor GreeterActor(responder):
  on message "Start":
    send Greet(self) to responder

actor ResponderActor():
  on message Greet(sender):
    send Greeting("Hello!") to sender
  on message Greeting(message):
    print message

function runActorSystem():
  create ActorSystem
  create ResponderActor
  create GreeterActor, passing ResponderActor reference
  send "Start" to GreeterActor
  wait for messages to process
  terminate ActorSystem