I am a newbie to SimPy and am trying to get the following done. Simulate processes, where each has a different time delay. Once the first process is done, i am interrupting other processes, which i catch. But once in the catch block all these processes resume again and the environment clock continues till all of them are done. I want the simulation to stop right after the first processes is done and then update remaining time on other processes and basically stop everything so the env.now time is at when the first process is done.
Sample code
class Main:
env = simpy.Environment()
res1 = Resource(env, list(), 10)
res2 = Resource(env, list(), 15)
res3 = Resource(env, list(), 20)
#Add other resources to each
res1.appendOtherResource(res2)
res1.appendOtherResource(res3)
res2.appendOtherResource(res1)
res2.appendOtherResource(res3)
res3.appendOtherResource(res2)
res3.appendOtherResource(res1)
Resources = list()
Resources.append(res1)
Resources.append(res2)
Resources.append(res3)
env.process(scheduleResources(Resources, env))
env.run()
def scheduleResources(Resources, env)
for resource in Resources:
env.process(resource.start())
Class Resource has a start and run method with the following: Also assume each resource has a processing time when it is instantiated: Each resource also has a reference to other resources, not showing code for all that to keep it short.
class Resource:
def __init__(self, env, otherResources, timeToProcess):
self.resource_process = None
self.otherResources = otherResources
self.env = env
self.timeToProcess = timeToProcess
def appendOtherResource(self, otherResource):
self.otherResources.append(otherResource)
def start(self):
yield (self.env.timeout(0))
self.resource_process = self.env.process(self.run())
def run(self):
try:
self.env.timeout(self.timeToProcess)
self.timeToProcess = 0
for res in self.otherResources:
if res.resource_process != None:
if res.resource_process.is_alive:
res.resource_process.interrupt()
except simpy.Interrupt as interrupt:
self.timeToProcess = self.timeToProcess - self.env.now
#How do i ensure that the process that is interrupted is killed after this step and does not continue
What happens currently is that the shortest resource process is done. Interrupt is called on all other resources, and the timeToProcess is updated correctly. But after this the environment runs to complete all resource processes and the env.now changes beyond the first stop that was intended.
I tried env.exit() but with no success. Is there any way in simpy to stop simulation immediately, no matter what processes are scheduled.
Regards
when you call env.run() the simulation runs until all events complete. The issues is when you interrupt you resources process, your resource processes are interrupted but not the timeout events in your processes. so your resource processes have all completed or been interrupted, but the env.run is still waiting for all the timeouts to complete before it ends the simulation.
env.run() has a until parameter. this parameter can be a number or a event. when it is a number that is the time unit the sim will end on. When it is a event, the simulation goes until the event fires.
I wrapped you resource processes in a env.all_of event. This event fires will all the events in its list have fired. and passed this to env.run
env.run(until=env.all_of(resource_processes))
I also made some other minor changes to get you code to run and to better trace events
Also not that you can resume the simulation by calling env.run() a second time
here is the code
import simpy
def scheduleResources(Resources, env):
# start the resource process and return a list of hte processes
process_list = []
for resource in Resources:
process_list.append(resource.start())
return(process_list)
class Resource:
def __init__(self, env, id, otherResources, timeToProcess):
self.id = id
self.resource_process = None
self.otherResources = otherResources
self.env = env
self.timeToProcess = timeToProcess
def appendOtherResource(self, otherResource):
self.otherResources.append(otherResource)
def start(self):
#yield (self.env.timeout(0))
self.resource_process = self.env.process(self.run())
return self.resource_process
def run(self):
try:
yield self.env.timeout(self.timeToProcess)
self.timeToProcess = 0
for res in self.otherResources:
if res.resource_process != None:
if res.resource_process.is_alive:
res.resource_process.interrupt()
print (self.id, "finished")
except simpy.Interrupt as interrupt:
print(self.id, "interupted")
self.timeToProcess = self.timeToProcess - self.env.now
def main():
env = simpy.Environment()
res1 = Resource(env, 1, list(), 10)
res2 = Resource(env, 2, list(), 15)
res3 = Resource(env, 3, list(), 20)
#Add other resources to each
res1.appendOtherResource(res2)
res1.appendOtherResource(res3)
res2.appendOtherResource(res1)
res2.appendOtherResource(res3)
res3.appendOtherResource(res2)
res3.appendOtherResource(res1)
Resources = list()
Resources.append(res1)
Resources.append(res2)
Resources.append(res3)
resource_processes = scheduleResources(Resources, env)
# stop when all the resources process ends
env.run(until=env.all_of(resource_processes))
#env.run()
print('end time', env.now)
main()