The system that I am modelling has objects that require maintenance in the form of a series of tasks. Currently in this model, they request a "work location", then once they have seized that, they request the necessary "worker" resources they need to complete the first task. The tasks are objects in a list that is an attribute of the object having maintenance done to it, and some of the task networks allow for multiple tasks to be completed in parallel.
As it stands, I have the task list being iterated over in a for loop, where a nested for loop then requests and seizes the necessary "workers" and then times out for the duration of the task once all the "workers" have been seized.
with self.location.request() as loc_req: # request work location
yield loc_req # wait for work location
for task in self.tasks[:]:
t_duration = task.calc_duration(self)
if t_duration == 0: # skip tasks where probability sets duration to 0
continue
needs = task.resources[:]
## check if available workers are useful; if not, release them
task_cur_resources = []
for res,req in self.resources['available'].copy():
if res.worker_id in needs:
self.resources['busy'].add((res,req))
task_cur_resources.append((res,req))
needs.remove(res.worker_id)
else:
res.release(req)
self.resources['available'].remove((res,req))
## acquire all resources needed for task
for need in needs[:]:
priority = len(needs) # prioritize tasks closer to meeting needs
res = self.location.workers[need] # set resource to worker of type need
req = res.request(priority) # save the request object
yield req # wait for resource
## stash resource and request in order to release later
task_cur_resources.append((res, req))
self.resources['busy'].add((res,req))
needs.remove(res.worker_id)
## perform task with task duration timeout
yield self.env.process(task.perform(self, t_duration))
## make resources available
for worker in task_cur_resources:
self.resources['busy'].remove(worker)
self.resources['available'].add(worker)
for res,req in self.resources['available']:
res.release(req)
self.resources['available'] = set()
The issue is that this does not allow for concurrent task completion. The tasks are done sequentially with normally distributed durations based on input params. How can I change this to allow for tasks to be done whenever their predecessors are done and the workers are available? I tried a while loop that iterated through the task list and scheduled tasks that had their predecessors complete, but I kept ending up with infinite loops due to my apparent misuse of SimPy and the yields. Any ideas?