How to know which resource is being used when using SimPy's AnyOf method?

Viewed 290

In my program, agents need to use some specific resources. I want to call all of the resources that are assigned for an agent at the same time and use the first available one.

Think about 3 servers and 4 agents.

agent1 can use server1,

agent2 can use server1 and server2,

agent3 can use server2 and server3,

agent4 can use server3

I am creating requests like below:

{server: server.request() for server in agent_2_server_list}

output:
{<simpy.resources.resource.Resource at 0x7fd091b215e0>: <Request() object at 0x7fd091d51d00>,
 <simpy.resources.resource.Resource at 0x7fd091b21700>: <Request() object at 0x7fd091d51b50>}

I am using env.any_of([request1, request2]) to use any of the above requests. However, I need to know which resource is used so that I can release it afterward. How can I do that?

1 Answers

env.any_of returns a dict of the first events that fired. Remember that both events can fire at the same time. Also remember that if only one event fires, the second event is still pending. So if you only want one event to fire you will have to check if both events fired and release one, or if only one event fired, to cancel the second event.

here is a example

"""
example of getting the first avalable resouce from 2 resouce pools

prorammer 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')
Related