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

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

Actor Simulation: Message Passing and State Management

Crystal

Goal -- WPM

Ready
Exercise Algorithm Area
1require "json"
2
3# Define message types
4struct IncrementMessage
5getter amount : Int32
6end
7
8struct GetValueMessage
9getter reply_to : Channel(Int32)
10end
11
12struct ActorState
13getter value : Int32
14
15def initialize(@value = 0)
16end
17
18def process_message(message : JSON::Any)
19case message["type"].as_s
20when "Increment"
21inc_msg = JSON.parse(message.to_json, into: IncrementMessage)
22@value += inc_msg.amount
23puts "Actor state updated. New value: #{@value}"
24when "GetValue"
25get_msg = JSON.parse(message.to_json, into: GetValueMessage)
26get_msg.reply_to.send(@value)
27puts "Actor sent current value."
28else
29puts "Unknown message type received."
30end
31end
32
33def get_current_value : Int32
34@value
35end
36end
37
38class Actor
39getter mailbox : Channel(JSON::Any)
40getter state : ActorState
41getter running : Bool
42
43def initialize(@state : ActorState)
44@mailbox = Channel(JSON::Any).new
45@running = false
46@actor_thread = nil
47end
48
49def start
50return if @running
51@running = true
52@actor_thread = spawn do
53run
54end
55puts "Actor started."
56end
57
58def stop
59return unless @running
60@running = false
61@mailbox.close
62@actor_thread.join if @actor_thread
63puts "Actor stopped."
64end
65
66def send_message(message : Hash(String, JSON::Any))
67@mailbox.send(message)
68end
69
70private def run
71while @running
72message = @mailbox.receive
73@state.process_message(message)
74end
75end
76end
77
78# Example Usage:
79# actor = Actor.new(ActorState.new)
80# actor.start
81
82# # Send increment messages
83# actor.send_message({"type" => "Increment", "amount" => 10}.to_json)
84# actor.send_message({"type" => "Increment", "amount" => 5}.to_json)
85
86# # Get current value
87# reply_channel = Channel(Int32).new
88# actor.send_message({"type" => "GetValue", "reply_to" => reply_channel}.to_json)
89
90# # Wait for reply
91# value = reply_channel.receive
92# puts "Received value from actor: #{value}"
93
94# # Stop the actor
95# actor.stop
Algorithm description viewbox

Actor Simulation: Message Passing and State Management

Algorithm description:

This Crystal code simulates an actor system using fibers and channels. A central `Actor` class manages a mailbox (channel) and an `ActorState` object. Actors process messages asynchronously, updating their state and potentially communicating with other actors. This pattern is fundamental for building concurrent, fault-tolerant systems where components operate independently.

Algorithm explanation:

Each `Actor` runs in its own fiber, processing messages from its `mailbox` channel. The `ActorState` object encapsulates the actor's data and logic for handling different message types. Messages are passed as JSON-encoded Hashes, which are then parsed into specific message structs (`IncrementMessage`, `GetValueMessage`). The `GetValueMessage` demonstrates request-reply pattern by including a reply channel. Actors communicate asynchronously, and state is managed internally, avoiding shared mutable state issues. Time complexity for processing a message is O(M) where M is the complexity of message processing (parsing and state update). Space complexity is O(C) where C is the channel capacity and O(S) for actor state.

Pseudocode:

Struct IncrementMessage:
  amount

Struct GetValueMessage:
  reply_to (channel)

Class ActorState:
  Initialize(value = 0)

  Process_message(message):
    Parse message to determine type
    If type is "Increment":
      Deserialize into IncrementMessage
      Update state.value += amount
      Print update
    If type is "GetValue":
      Deserialize into GetValueMessage
      Send state.value to get_msg.reply_to channel
      Print sent value
    Else:
      Print unknown message

  Get_current_value():
    Return value

Class Actor:
  Initialize(state):
    Set mailbox = new Channel
    Set state = state
    Set running = false
    Set actor_thread = nil

  Start():
    If not running:
      Set running = true
      Spawn a fiber running run()
      Print "Actor started."

  Stop():
    If running:
      Set running = false
      Close mailbox channel
      Join actor_thread
      Print "Actor stopped."

  Send_message(message):
    Send message to mailbox channel

  Run():
    While running:
      Receive message from mailbox
      Call state.process_message(message)