Event

Events are a specialized Components that serve to trigger an action in the future.

Being a subclass of Component, all usual methods of Component are available.

In contrast to ordinary components, events are hardly ever subclassed (actually that’s the main purpose of an event).

An event requires an action, which should be a callable. In most cases that will be a lambda function. But if the action involves more functionality, an ordinary function is also possible.

It is common, although not required that the action is triggered for a moment in the future, either by specifying an at or a delay parameter.

Creation of an event is easy:

wake_up = sim.Event(action=lambda: print("Wake up!"), name="wake_up", delay=10)

Now, at t=now() + 10, the wake_up event will perform the specified action and thus print “Wake up!”

The most common use case is to activate the current component after a certain time, regardless of the normal process flow. E.g.:

class Client(sim.Component):
    def process(self):
        timer = sim.Event(action= lambda: self.activate(), name='timer', delay=10)
        self.hold(sim.Uniform(0,20))
        timer.cancel()  # this can be done even is the action was taken and timer is a data component
        if timer.action_taken():
            print("balked, because I had to wait for 10 minutes")
            return
        print("do stuff ...")

Here’s a version of the Bank model with events:

 1# Example - bank, 3 clerks, reneging.py
 2import salabim as sim
 3
 4
 5class Customer(sim.Component):
 6    def process(self):
 7        if len(waitingline) >= 5:
 8            env.number_balked += 1
 9            env.print_trace("", "", "balked")
10            print(env.now(), "balked", self.name())
11            self.cancel()
12        self.enter(waitingline)
13        for clerk in clerks:
14            if clerk.ispassive():
15                clerk.activate()
16                break  # activate only one clerk
17        event = sim.Event(action=lambda: self.activate(), delay=50)
18        self.passivate()  # if not serviced within this time, renege
19        event.cancel()  # cancel also if action is already taken
20
21        if self in waitingline:
22            self.leave(waitingline)
23            env.number_reneged += 1
24            env.print_trace("", "", "reneged")
25        else:
26            self.passivate()  # wait for service to be completed
27
28
29class Clerk(sim.Component):
30    def process(self):
31        while True:
32            while len(waitingline) == 0:
33                self.passivate()
34            self.customer = waitingline.pop()
35            self.customer.activate()  # get the customer out of it's passivate()
36            self.hold(30)
37            self.customer.activate()  # signal the customer that's all's done
38
39
40env = sim.Environment()
41sim.ComponentGenerator(Customer, iat=sim.Uniform(5, 15))
42env.number_balked = 0
43env.number_reneged = 0
44clerks = [Clerk() for _ in range(3)]
45
46waitingline = sim.Queue("waitingline")
47env.run(duration=300000)
48waitingline.length.print_histogram(30, 0, 1)
49waitingline.length_of_stay.print_histogram(30, 0, 10)
50print("number reneged", env.number_reneged)
51print("number balked", env.number_balked)

It is possible to add an action_string to be used in the trace with the parameter action_string.

An event has a couple of useful methods:

Event.action() allows to change/query the action to be taken

Event.action_string() allows to change/query the text to be printed when the acton is taken

Event.action_taken() is False before the action is taken, True afterwards