Documentation
¶
Overview ¶
Package steps provides a simple, fast, discrete event simulator in Go.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Ticker ¶
Ticker schedules an event to run at a regular interval. For more complex cronjobs etc., have a look at something like 1.
Example ¶
ExampleTicker shows how to use the Ticker helper to schedule events at regular intervals.
sim := NewSimulation()
Ticker(sim, sim.Now, 3*time.Second, func(s *Simulation) {
fmt.Println("Actor:", sim.Now)
})
whenToStop := sim.Now.Add(15 * time.Second)
sim.RunUntil(whenToStop)
Output: Actor: 0001-01-01 00:00:00 +0000 UTC Actor: 0001-01-01 00:00:03 +0000 UTC Actor: 0001-01-01 00:00:06 +0000 UTC Actor: 0001-01-01 00:00:09 +0000 UTC Actor: 0001-01-01 00:00:12 +0000 UTC Actor: 0001-01-01 00:00:15 +0000 UTC
Types ¶
type Action ¶
type Action func(*Simulation)
type BinarySemaphore ¶
type BinarySemaphore struct {
// contains filtered or unexported fields
}
BinarySemaphore is a semaphore that can be used to synchronize actions. It is a counting semaphore with a maximum of 1. Since a simulation can only run one action at a time, this library does not implement any mutex[1]
[1] https://en.wikipedia.org/wiki/Lock_(computer_science)#Mutexes_vs._semaphores
Example ¶
ExampleBinarySemaphore demonstrates how to use the BinarySemaphore to synchronize actions. It simulates processing ten (10) items, one (1) at a time.
sim := NewSimulation()
sem := NewBinarySemaphore(sim)
// Simulate processing ten (10) items, one (1) at a time.
timeToProcess := 10 * time.Second
for i := range 10 {
sem.Acquire(func(sim *Simulation) {
// We have now acquired the semaphore and can start processing.
fmt.Println(sim.Now, "Processing item", i)
sim.Schedule(Event{When: sim.Now.Add(timeToProcess), Action: func(sim *Simulation) {
fmt.Println(sim.Now, "Done processing item", i)
sem.Release()
}})
})
}
sim.RunUntilDone()
Output: 0001-01-01 00:00:00 +0000 UTC Processing item 0 0001-01-01 00:00:10 +0000 UTC Done processing item 0 0001-01-01 00:00:10 +0000 UTC Processing item 1 0001-01-01 00:00:20 +0000 UTC Done processing item 1 0001-01-01 00:00:20 +0000 UTC Processing item 2 0001-01-01 00:00:30 +0000 UTC Done processing item 2 0001-01-01 00:00:30 +0000 UTC Processing item 3 0001-01-01 00:00:40 +0000 UTC Done processing item 3 0001-01-01 00:00:40 +0000 UTC Processing item 4 0001-01-01 00:00:50 +0000 UTC Done processing item 4 0001-01-01 00:00:50 +0000 UTC Processing item 5 0001-01-01 00:01:00 +0000 UTC Done processing item 5 0001-01-01 00:01:00 +0000 UTC Processing item 6 0001-01-01 00:01:10 +0000 UTC Done processing item 6 0001-01-01 00:01:10 +0000 UTC Processing item 7 0001-01-01 00:01:20 +0000 UTC Done processing item 7 0001-01-01 00:01:20 +0000 UTC Processing item 8 0001-01-01 00:01:30 +0000 UTC Done processing item 8 0001-01-01 00:01:30 +0000 UTC Processing item 9 0001-01-01 00:01:40 +0000 UTC Done processing item 9
func NewBinarySemaphore ¶
func NewBinarySemaphore(sim *Simulation) *BinarySemaphore
NewBinarySemaphore creates a new binary semaphore.
func (*BinarySemaphore) Acquire ¶
func (s *BinarySemaphore) Acquire(a Action)
Acquire acquires the semaphore. If the semaphore is already acquired, the action will be scheduled to run when the semaphore is released. Do not forget to call Release() when the action is done (unless you want to hold the semaphore for longer).
func (*BinarySemaphore) Release ¶
func (s *BinarySemaphore) Release()
Release releases the semaphore.
type Condition ¶
type Condition struct {
// contains filtered or unexported fields
}
Condition is a condition that can be used to synchronize actions. Multiple actions can be waiting for the same condition, and be triggered by a Signal or Broadcast, similarly to sync.Cond.
Example ¶
ExampleCondition demonstrates how to use the Condition to synchronize actions. It simulates processing ten (10) items, rate-limited to one item per second.
sim := NewSimulation()
c := NewCondition(sim)
itemsToProcess := 10
for range itemsToProcess {
c.Wait(func(sim *Simulation) {
fmt.Println(sim.Now, "Processing...")
})
}
Ticker(sim, sim.Now, time.Second, func(sim *Simulation) {
c.Signal()
})
// Deliberately not using sim.RunUntilDone() here since the Ticker will run indefinitely.
sim.RunUntil(sim.Now.Add(time.Duration(2*itemsToProcess) * time.Second))
Output: 0001-01-01 00:00:00 +0000 UTC Processing... 0001-01-01 00:00:01 +0000 UTC Processing... 0001-01-01 00:00:02 +0000 UTC Processing... 0001-01-01 00:00:03 +0000 UTC Processing... 0001-01-01 00:00:04 +0000 UTC Processing... 0001-01-01 00:00:05 +0000 UTC Processing... 0001-01-01 00:00:06 +0000 UTC Processing... 0001-01-01 00:00:07 +0000 UTC Processing... 0001-01-01 00:00:08 +0000 UTC Processing... 0001-01-01 00:00:09 +0000 UTC Processing...
func NewCondition ¶
func NewCondition(sim *Simulation) *Condition
NewCondition creates a new condition.
func (*Condition) Broadcast ¶
func (c *Condition) Broadcast()
Broadcast wakes up all actions waiting for this condition. Actions are woken up in the order they were waiting.
func (*Condition) Cancel ¶
func (c *Condition) Cancel(id ConditionActionID) bool
Cancel cancels an action waiting for this condition. Returns true if the action was found and removed, false otherwise (e.g. it was already executed, never existed, or was previously cancelled).
func (*Condition) Signal ¶
func (c *Condition) Signal()
Signal wakes up one action waiting for this condition. Actions are woken up in the order they were waiting.
func (*Condition) Wait ¶
func (c *Condition) Wait(a Action) ConditionActionID
type ConditionActionID ¶
type ConditionActionID int
type CountingSemaphore ¶
type CountingSemaphore struct {
// contains filtered or unexported fields
}
CountingSemaphore is a semaphore that can be used to synchronize actions and limit the number of concurrent actions (in the simulation sense). It is a counting semaphore with a maximum of count.
Example ¶
ExampleCountingSemaphore demonstrates how to use the CountingSemaphore to synchronize actions. It simulates processing ten (10) items, three (3) at a time.
sim := NewSimulation()
sem := NewCountingSemaphore(sim, 3)
// Simulate processing 10 items, 3 at a time.
timeToProcess := 10 * time.Second
itemsToProcess := 10
for i := range itemsToProcess {
sem.Acquire(func(sim *Simulation) {
// We have now acquired the semaphore and can start processing.
fmt.Println(sim.Now, "Processing item", i)
sim.Schedule(Event{When: sim.Now.Add(timeToProcess), Action: func(sim *Simulation) {
fmt.Println(sim.Now, "Done processing item", i)
sem.Release()
}})
})
}
sim.RunUntilDone()
Output: 0001-01-01 00:00:00 +0000 UTC Processing item 0 0001-01-01 00:00:00 +0000 UTC Processing item 1 0001-01-01 00:00:00 +0000 UTC Processing item 2 0001-01-01 00:00:10 +0000 UTC Done processing item 0 0001-01-01 00:00:10 +0000 UTC Processing item 3 0001-01-01 00:00:10 +0000 UTC Done processing item 1 0001-01-01 00:00:10 +0000 UTC Processing item 4 0001-01-01 00:00:10 +0000 UTC Done processing item 2 0001-01-01 00:00:10 +0000 UTC Processing item 5 0001-01-01 00:00:20 +0000 UTC Done processing item 3 0001-01-01 00:00:20 +0000 UTC Processing item 6 0001-01-01 00:00:20 +0000 UTC Done processing item 4 0001-01-01 00:00:20 +0000 UTC Processing item 7 0001-01-01 00:00:20 +0000 UTC Done processing item 5 0001-01-01 00:00:20 +0000 UTC Processing item 8 0001-01-01 00:00:30 +0000 UTC Done processing item 6 0001-01-01 00:00:30 +0000 UTC Processing item 9 0001-01-01 00:00:30 +0000 UTC Done processing item 7 0001-01-01 00:00:30 +0000 UTC Done processing item 8 0001-01-01 00:00:40 +0000 UTC Done processing item 9
func NewCountingSemaphore ¶
func NewCountingSemaphore(sim *Simulation, count int) *CountingSemaphore
NewCountingSemaphore creates a new counting semaphore.
func (*CountingSemaphore) Acquire ¶
func (s *CountingSemaphore) Acquire(a Action)
Acquire acquires the semaphore. If the semaphore is already acquired, the action will be scheduled to run when the semaphore is released. Do not forget to call Release() when the action is done (unless you want to hold the semaphore for longer).
func (*CountingSemaphore) Release ¶
func (s *CountingSemaphore) Release()
Release releases the semaphore.
type Event ¶
type Event struct {
// When is the time at which the event should be processed as measured from the start of the simulation.
When time.Time
// Action is the function to call when the event is to be processed.
Action Action
}
Event represents an event that will be processed as soon as possible after a specific time.
type EventID ¶
type EventID int
EventID is the ID of a scheduled event. It is mostly used if you need to cancel a scheduled event before it is executed.
type Simulation ¶
type Simulation struct {
// Now represents the current point in time in the simulation. It is not recommended to modify this value during a simulation.
Now time.Time
// contains filtered or unexported fields
}
Simulation runs a discrete event simulation.
Example ¶
ExampleSimulation shows how to use the Simulation type to schedule a single event and run a simulation until a given time.
sim := NewSimulation()
sim.Schedule(Event{When: sim.Now.Add(10 * time.Second), Action: func(s *Simulation) {
fmt.Println("Actor 1:", sim.Now)
}})
sim.Schedule(Event{When: sim.Now.Add(time.Second), Action: func(s *Simulation) {
fmt.Println("Actor 2:", sim.Now)
}})
sim.RunUntilDone()
Output: Actor 2: 0001-01-01 00:00:01 +0000 UTC Actor 1: 0001-01-01 00:00:10 +0000 UTC
func (*Simulation) Cancel ¶
func (s *Simulation) Cancel(id EventID) bool
Cancel cancels an event scheduled to the simulation. Returns true if the event was found and cancelled, false if the event was not found (never scheduled, or it was already executed).
func (*Simulation) RunUntil ¶
func (s *Simulation) RunUntil(until time.Time)
RunUntil runs the simulation until the given time or there are no more events to process.
func (*Simulation) RunUntilDone ¶
func (s *Simulation) RunUntilDone()
RunUntilDone runs the simulation until there are no more events to process.
func (*Simulation) Schedule ¶
func (s *Simulation) Schedule(e Event) EventID
Schedule schedules an event to be executed at the given time by the simulator. It returns the ID of the event, which can be used to cancel the event before it is executed.
func (*Simulation) Step ¶
func (s *Simulation) Step() bool
Step advances the simulation by one event. It returns true if the simulation advanced, false if there were no events to process.