'overlapping' resources and multiple resources

202 views
Skip to first unread message

Glen MacLachlan

unread,
Jun 12, 2021, 2:58:18 PM6/12/21
to python-simpy
Hello, 

I have implemented a simulation using simpy of a job scheduler for high performance computing systems but need to extend the model and I'm not sure if or how simpy can be used to achieve what I'm looking for. 

The additional features I'm trying to add can probably be best explained by analogy. Suppose a customer arrives at a restaurant that has two different kinds of tables available
  1. smoking
  2. non-smoking
This is how the simulation currently works but suppose now the customer could elect to say 'first available' meaning they don't have a preference. Now the options are
  1. smoking
  2. non-smoking
  3. First available (meaning both 1 and 2 overlap)

The (pseudo) code would probably look something like

env = simpy.Environment()
smoking_table = simpy.PriorityResource(env, capacity = 3)
nonsmoking_table = simpy.PriorityResource(env, capacity = 10)

def open_for_business(env):
    for i in range(NUM_OF_JOBS):
        if PREFERENCE == 'nonsmoking'
            seat_guest(env,nonsmoking_table)
        if PREFERENCE == 'smoking'
            seat_guest(env,smoking_table)
        else:
            ###Dunno what to do in this case

def seat_guest(env,table):
      with table.request() as req:
            yield req 
            yield env.timeout(TableBusy)

I'm not too worried about syntax here - I can fix that myself. I'm just trying to get the idea for what the design pattern (if there is one) would look like in simpy.

Secondly, suppose the customer needs to request more that one resource (table in this instance). Suppose the customer tells the maitre d' that they're waiting for others to arrive and will need two tables. Is it possible to hold back tables until the rest of the party arrives with something like with table.request(2) as req:?

Hope this wasn't too awkward of an explanation. Happy to clarify if need be. 

Regards, 
Glen


Michael Gibbs

unread,
Jul 3, 2021, 11:02:37 AM7/3/21
to python-simpy
You need to make two request and us yield env.any_of([req1, req2]) to wait for one of the requests to be filled
but when the yield ends you need to cancel the the request not filled, or release one resource if both are filled

here is a quick example

"""
example of getting the first available resource from 2 resource pools

programmer Michael R. Gibbs
"""
import simpy

def seat(env, id, smokingRes, nonSmokingRes):
    """
    Main process of getting the first avaialbe table
    from one of two resouce pools (smoking, non smoking)
    """

    # make a request from both resouce pools
    print(env.now, id, "waiting for a table")
    smokeReq = smokingRes.request()
    nonSmokeReq = nonSmokingRes.request()

    # wait for one of the requests to be filled
    seat = yield env.any_of([smokeReq,nonSmokeReq])
    
    seatList = list(seat.keys())

    # it is possible that both resources are avaliable
    # and both request get filled
    seated = seatList[0]

    if len(seatList) > 1:
        # both requests got filled, need to release one
        print(env.now, id, "both were available, releasing one")
        if seated == smokeReq:
            nonSmokingRes.release(nonSmokeReq)
        else:
            smokingRes.release(smokeReq)
    else:
        # only one request was filled, need to cancel the other request
        print(env.now, id, 'got a seat, cancel other request')
        if smokeReq in seatList:
            nonSmokeReq.cancel()
        else:
            smokeReq.cancel()

    yield env.timeout(5)
    if seated == smokeReq:
        smokingRes.release(seated)
    else:
        nonSmokingRes.release(seated)
    print(env.now, id, "released seat")

def test(env, smokingRes, nonSmokingRes):
    """
    test when four people want 2 tables
    """
    env.process(seat(env,1,smokingRes,nonSmokingRes))
    yield env.timeout(1)
    env.process(seat(env,2,smokingRes,nonSmokingRes))
    yield env.timeout(1)
    env.process(seat(env,3,smokingRes,nonSmokingRes))
    yield env.timeout(1)
    env.process(seat(env,4,smokingRes,nonSmokingRes))


env = simpy.Environment()
smokingRes = simpy.Resource(env, capacity=1)
nonSmokingRes = simpy.Resource(env, capacity=1)

env.process(test(env,smokingRes,nonSmokingRes))


env.run(until=100)

print ('done')

Reply all
Reply to author
Forward
0 new messages