Reputation: 21
simpy newbie here. I just started to make Speaker-Moderator simulation with simpy. Here is my code
import simpy
def speaker(env):
try:
print("Speaker start to talk at: {}".format(env.now))
speak_time = 40
print ("Speaker want to speak for {}".format(speak_time))
yield env.timeout(speak_time)
print ("Speaker finish the talk at: {}".format(env.now))
except simpy.Interrupt as interrupt:
print (interrupt.cause)
def moderator(env):
for i in range(3):
print("Moderator let the speaker number {} to begin the speak".format(i))
speaker_proc = env.process(speaker(env))
print("Time now: {}".format(env.now))
time_limit = env.timeout(30)
results = yield speaker_proc | time_limit
print("Moderator check whether speaker passed the time limit or no")
print("Time limit passed: {}".format (speaker_proc not in results))
if speaker_proc not in results:
print("Time now: {}".format(env.now))
speaker_proc.interrupt()
print ("Moderator stop the talk at: {}".format(env.now))
print()
print()
env = simpy.Environment()
env.process(moderator(env))
env.run()
When I run it with speak_time > 30 or speak_time < 30, It has no problem but if I change speak_time in function speaker become 30 it will get error like this:
RuntimeError: <Process(speaker) object at 0x9e17930> has terminated and cannot be interrupted.
What happened?
Upvotes: 2
Views: 1553
Reputation: 3232
You hit a strange corner case here. While the behavior you observed is totally intended, it is not very easy to understand for SimBy newbies.
I added two print()
to your moderator()
process to show what’s going on:
import simpy
def speaker(env):
try:
print("Speaker start to talk at: {}".format(env.now))
speak_time = 30
print("Speaker want to speak for {}".format(speak_time))
yield env.timeout(speak_time)
print("Speaker finish the talk at: {}".format(env.now))
except simpy.Interrupt as interrupt:
print(interrupt.cause)
def moderator(env):
for i in range(3):
print("Moderator let the speaker number {} to begin the speak".format(i))
speaker_proc = env.process(speaker(env))
print("Time now: {}".format(env.now))
time_limit = env.timeout(30)
print('Timeout created')
results = yield speaker_proc | time_limit
print("Moderator check whether speaker passed the time limit or no")
print("Time limit passed: {}".format(speaker_proc not in results))
if speaker_proc not in results:
print("Time now: {}".format(env.now))
print(speaker_proc.is_alive)
speaker_proc.interrupt()
print("Moderator stop the talk at: {}".format(env.now))
print()
print()
env = simpy.Environment()
env.process(moderator(env))
env.run()
The output:
Moderator let the speaker number 0 to begin the speak
Time now: 0
Timeout created
Speaker start to talk at: 0
Speaker want to speak for 30
Speaker finish the talk at: 30
Moderator check whether speaker passed the time limit or no
Time limit passed: True
Time now: 30
False
Traceback (most recent call last):
So what happend?
The moderator is active until its first yield
. During that time, it
creates the speaker process and the timeout.
The timeout is immediately triggered and added to the event queue.
The moderator yields the conditon event.
The speaker runs and creates its timeout. It is also immediately triggered and scheduled (at the same time as the moderator's timeout, but it is inserted after it in the event queue).
The Condition event is triggered when the moderator's timeout is processed.
When the moderator is resumed, the condition event only holds the result of
moderator's timeout, but the speaker processes terminated, too. You can
check this via the speaker_proc.is_alive
property.
This guide contains some more in-depth information about this topic.
Upvotes: 1