Search code examples
pythonsimpy

Example of SimPy event that is triggered but not processed


Just like this question, I don't understand what triggered means for a SimPy event. The only answer posted does not clarify it for me.

The docs say an event:

  • might happen (not triggered),
  • is going to happen (triggered) or
  • has happened (processed).

I originally thought those corresponded to:

  • event defined
  • event yielded
  • code in event completes execution

But then I found through experimentation that was wrong. I have not been able to create an example for which I can print p.triggered and p.processed for some process p and have the first be True and the second False. They're always either both True or both False.

So my question is, can anyone give code of an example (ideally as simple as possible) for which there exists some moment of time that a process is triggered but not processed?

Ideally, it would include an explanation of "triggered" that matches the example.


Solution

  • This stuff is not clear, but my understanding is that when you use env.process() to convert one of your processes to a event, that event does not get triggered until you exit your process, not when it hits a yield. So if you write a process with a infinite loop, it will always be in that might happen (not triggered) state.

    Events are not marked as processed until all events that can be triggered at a time x, are triggered. I think this allows for events to talk to each other and add callbacks, before callbacks get executed. I'm not sure what happens if a callback creates a new event that is immediately triggered.

    here is some code to show the event flow

    """
    Quick demo showing the states of events over time
    
    Three events are created which all expire at the same time.
    One event has a callback
    
    Looks like events are not marked as triggered until they exit their process.
    And callback are not processed until all triggering is done.
    
    Programmer: Michael R. Gibbs
    """
    
    import simpy
    
    class EventCheck():
        """
        class with a event process that checks the state
        of a list of events.
        """
    
        def __init__(self, env, name):
            self.eventList = []
            self.env = env
            self.name = name
    
            # create the event
            self.e = self.env.process(self.e_process())
    
        def set_event_list(self, list):
            """
            The list of objects of this class type
            """
            self.eventList = list
    
        def check_events(self):
            """
            print out the state of a list of events
            """
            for obj in self.eventList:
                print(obj.name, obj.e.triggered, obj.e.processed)
    
        def e_process(self):
            """
            The event that get turned into a evnet with env.process()
            call the method that prints out the states of a list of events
            """
            print(self.env.now, self.name, "created")
            yield self.env.timeout(2)
            print(self.env.now,self.name, "timeout finished")
            self.check_events()
            print(self.env.now,self.name, "finish process")
    
    def pre_check(env, list):
        """
        Prints out the states of a event before its trigger time
        """
        
        yield env.timeout(1)
        print(env.now, "pre trigger")
        list[0].check_events()
    
    def watcher(env, e):
        """
        Shows how a process sees a event
        """
        print(env.now, "watching")
        print(e.triggered, e.processed)
        yield e
    
        print(env.now, "done watching")
        print(e.triggered, e.processed)
    
    def my_callback(e):
        """
        Shows how a callback sees a event calling it
        """
        print("callback")
        print(e.triggered, e.processed)
    
    env = simpy.Environment()
    
    # create three events checkers, each has its own event
    e_list = [
        EventCheck(env, "e1"),
        EventCheck(env, 'e2'),
        EventCheck(env, 'e3'),    
    ]
    
    # give one event a callback
    e_list[0].e.callbacks.append(my_callback)
    
    # assing each checker the same list of events
    for e in e_list:
        e.set_event_list(e_list)
    
    # start the other process that show a events state
    env.process(pre_check(env, e_list))
    
    env.process(watcher(env, e_list[0].e))
    
    env.run(10)
    
    # show a events state after its trigger time
    print(env.now, "post trigger")
    e_list[0].check_events()
    

    and here is the output I got

    0 e1 created
    0 e2 created
    0 e3 created
    0 watching
    False False
    1 pre trigger
    e1 False False
    e2 False False
    e3 False False
    2 e1 timeout finished
    e1 False False
    e2 False False
    e3 False False
    2 e1 finish process
    2 e2 timeout finished
    e1 True False
    e2 False False
    e3 False False
    2 e2 finish process
    2 e3 timeout finished
    e1 True False
    e2 True False
    e3 False False
    2 e3 finish process
    callback
    True True
    2 done watching
    True True
    10 post trigger
    e1 True True
    e2 True True
    e3 True True