I'm dealing with a queue simulation related to a Cafe counter. This counter has 6 chairs, thus serving at most 6 people at the same time. Customers will arrive in parties. The number of customers in each party can be equal to 1, 2, 3, 4, 5, or 6 with the same probability. The amount of time each party spends in the restaurant after being seated is equal to 0.5 units of time. Assume that multiple parties may share the counter. The order of service is first come first serve. Assume the next party has a size of x. The party will be seated when at least x empty seats become available. The restaurant will finish serving all parties that arrive before t=12 and then close. The parties that arrive after t=12 will be turned away. The below are the arrival times for each party.
arrival_times=np.array([ 0.0473792 , 1.06007777, 2.02933004, 2.37675438, 2.69755975,
3.50251282, 5.98208415, 6.14630716, 7.3503128 , 7.60377882,
8.22431782, 8.5749094 , 8.98564659, 9.12636855, 9.75145154,
11.01328947])
My original code looks like this way:
import numpy as np
import simpy
def arrival(arrival_times):
i=0
inter_arrivals = arrival_times
for inter_arrival in inter_arrivals:
yield env.timeout(inter_arrival)
i+=1
Outcomes["arrival"].append(env.now)
env.process(service(i))
def service(i):
#requesting the front desk
rqt = resource.request()
yield rqt
service_time = 0.5
yield env.timeout(service_time)
resource.release(rqt)
Outcomes["depart"].append(env.now)
Outcomes["id"].append(i)
Outcomes["customers"].append(np.np.random.randint(1,7))
Outcomes = {"arrival":[],"depart":[],"id":[],"customers":[]}
env = simpy.Environment()
resource = simpy.Resource(env)
env.process(arrival(arrival_times))
T = 12
env.run(until=T)
arrival_n = np.array(Outcomes["arrival"])
depart_n = np.array(Outcomes["depart"])
id_n = np.array(Outcomes["id"])
customer_n = np.array(Outcomes["customers"])
But my code requires that only one party can occupy the counter. And another party can get service after them. Could someone explain how to simulate the queue such that different parties can share the counter? Thank you very much. I see there is a function called Simpy.AllOf(), which might be useful and will process events when all of the events in the list have been triggered. But I still have no idea.
looks like you have a resource pool for the counter. You need a resource pool for the 6 counter stools. Everyone in the party needs to make a resource request for a stool and when everyone in the party has a stool, then they can be seated and served. After the party is severed, then each person will need to release their seized stool. Note there is a simpy.events.AllOf to make one yield for many events
Here is my quick code example
"""
Serving parties at a cafe couter
parties are seated fifo
there must be enough available seats to seat the
entire party befor the party is dequeued and seated
more then one party can be at the cafe counter at a time
Programmer: Michael R. Gibbs
"""
import simpy
import random
def gen_arrivals(env, arrival_sched, partyQ, seats):
"""
use a arrival schedule to create parties of size 1 to 6
and put them in to a wait queue
"""
i = 0
for next_arrive in arrival_sched:
gap = next_arrive - env.now
yield env.timeout(gap)
# next arrial time has been reacked
# create a party
i+= 1
party = {
"party_id": i,
"arrive_time": env.now,
"party_size": random.randrange(1,6)
}
# put party in queue
yield partyQ.put(party)
print(f"{env.now:06.3f}",f"party {party['party_id']} has arrived and needs {party['party_size']} seats, {6 -seats.count} seats avaliable")
def seat_party(env, partyQ, counter_seats):
"""
process the seatting queue, FIFO
next party will block until there
are enough seats for the entire party,
even if a latter party
can fit at the counter
"""
while True:
party = yield partyQ.get()
# get seat request for each person in party
seat_requests = []
for _ in range(party['party_size']):
rqst = counter_seats.request()
seat_requests.append(rqst)
# save the seats so we can release them lator
party['seat_requests'] = seat_requests
# yield until ALL the requests have been filled
# since we are doing one party at a time, there
# is not deadlock contention for seats between the parties
yield simpy.events.AllOf(env, seat_requests)
print(f"{env.now:06.3f}",f"party {party['party_id']} has been seated taking {party['party_size']} seats, {6 -counter_seats.count} seats avaliable")
# once seated serve async so we can immediatly start
# seating the next party, in case there still enough
# seats to seat the next party imediatly
env.process(serve_party(env, party, counter_seats))
def serve_party(env, party, counter_seats):
"""
serve the party then release the seats
back to the counter seat resource pool
"""
yield env.timeout(0.5)
for seat_request in party['seat_requests']:
yield counter_seats.release(seat_request)
# and the party leaves
print(f"{env.now:06.3f}",f"party {party['party_id']} has been served relasing {party['party_size']} seats, {6 -counter_seats.count} seats avaliable")
""" schedule of arrial times for parties """
arrival_times=[ 0.0473792 , 1.06007777, 2.02933004, 2.37675438, 2.69755975,
3.50251282, 5.98208415, 6.14630716, 7.3503128 , 7.60377882,
8.22431782, 8.5749094 , 8.98564659, 9.12636855, 9.75145154,
11.01328947]
# start simulation and kick off arrival generation, and queue processing
env = simpy.Environment()
counter_seats = simpy.Resource(env, capacity=6)
partyQ = simpy.Store(env,99)
env.process(gen_arrivals(env, arrival_times, partyQ, counter_seats))
env.process(seat_party(env, partyQ,counter_seats))
env.run(24)