Process 3 requires both resources A and B, and can only start after process 1 (by resource A) and process 2 (by resource B) have been completed. The code below seems to perform as desired, but the if / else statement looks very inelegant. Is there a 'better' way of accomplishing the same behavior?
def orchestration(self):
# Request resources A and B
req_resourceA = self.resourceA.request()
req_resourceB = self.resourceB.request()
# Wait until first resource is available (will change throughout simulation)
available_rec = yield.self.env.any_of([req_resourceA, req_resourceB])
if list(available_rec.keys())[0] == resourceA:
proc1 = self.env.process(self.process1())
yield resourceB
proc2 = self.env.process(self.process2())
else:
proc2 = self.env.process(self.process2())
yield resourceA
proc1 = self.env.process(self.process1())
# Start process 3 only after processes 1 and 2 have been completed
yield proc1 & proc2
yield self.env.timeout(process3_time)
# Manually release both resource requests
self.resourceA.release(req_resourceA)
self.resourceB.release(req_resourceB)
In this solution I run process 1 and 2 in parallel instead of in sequence and used a all_of to wait for both processes to finish. This should reduce some idle time for the resources. Process 1 and 2 also grabs the resource they need, but do not release it. Instead they return the request so it can be passed to process 3. I pass the resource requests to process 3 thinking process 3 would know when to release each resource. for example process 3 could release resource A, do some more stuff, then release resource B
"""
One way steps can be sequcenced
In this example the pre steps are run in parallel
rather the sequentially
Programmer: Michael R. Gibbs
"""
from urllib import request
import simpy
import random
def process1(env, resPool):
"""
Simple process that grabs a resource and does some processing
The resource request is not released, but returned to the calling process
"""
resRequest = resPool.request()
yield resRequest
print(f'{env.now:0.2f} process 1 has resource and started')
yield env.timeout(random.randint(1,5))
print(f'{env.now:0.2f} process 1 has finish')
return resRequest
def process2(env, resPool):
"""
another simple process that grabs a resource and does some processing
The resource request is not released, but returned to the calling process
"""
resRequest = resPool.request()
yield resRequest
print(f'{env.now:0.2f} process 2 has resource and started')
yield env.timeout(random.randint(1,5))
print(f'{env.now:0.2f} process 2 has finish')
return resRequest
def process3(env, resourceAPool, requestA, resourceBPool, requestB):
"""
Final process that reuses resouces from process1 and process2
which this process is dependant on
"""
print(f'{env.now:0.2f} process 3 started')
yield env.timeout(random.randint(1,5))
resourceAPool.release(requestA)
resourceBPool.release(requestB)
print(f'{env.now:0.2f} process 3 finish')
def endToEndProcessing(env, resourceAPool, resourceBPool):
"""
the end to end processes
where process1 and process2 must complete before process 3 can start
"""
while True:
# start each pre process, but do not yeild so they runn in parallel
proc1 = env.process(process1(env,resourceAPool))
proc2 = env.process(process2(env,resourceBPool))
# wait for both processes to finish
preProcesses = yield env.all_of([proc1, proc2])
# get resource requests and pass to process 3
reqA = preProcesses[proc1]
reqB = preProcesses[proc2]
yield env.process(process3(env, resourceAPool, reqA, resourceBPool, reqB))
env = env = simpy.Environment()
resourceAPool = simpy.Resource(env, capacity=1)
resourceBPool = simpy.Resource(env, capacity=1)
env.process(endToEndProcessing(env, resourceAPool, resourceBPool))
env.run(100)