I'm using Simpy to simulate a queue and i need the function representing the service center to not get orders from the Store queue unless a condition is true. but when i add the if statement line all the other process in the environment stopes giving feedback as if this process it using all the computational power. i don't understand why it is acting they way it douse because it worked perfectly before i added the if statement.
here is the code for the function representing the service center:
order_queue
is simpy.store(env)
format_time
just formats the time into hours, minuets, and seconds
before adding the if statment:
def process_orders(env, order_queue):
while True:
order = yield order_queue.get()
print(f"{format_time(env.now)}: {order.name} in service centers")
order.exit_time = env.now
#pauses this function for the preparation time, mimicking the service center creating the order
yield env.timeout(order.prep_time)
waiting_time = order.exit_time - order.placement_time
print(f"{format_time(env.now)}: {order.name} exited at {env.now:.3f} minutes. Waiting time: {waiting_time:.3f} minutes.")
waiting_times.append(waiting_time)
after adding the if statement:
def process_orders(env, order_queue):
while True:
if (len(order_queue.items) > 0) and (round(env.now, 5) >= round(order_queue.items[-1].start_prep, 5)):
order = yield order_queue.get()
print(f"{format_time(env.now)}: {order.name} in service centers")
order.exit_time = env.now
# pauses this function for the preparation time, mimicking the service center creating the order
yield env.timeout(order.prep_time)
waiting_time = order.exit_time - order.placement_time
print(f"{format_time(env.now)}: {order.name} exited at {env.now:.3f} minutes. Waiting time: {waiting_time:.3f} minutes.")
waiting_times.append(waiting_time)
i tried to have simple if statements containing the same condition and printing when it enters them and commenting out the rest of the function. the if statements worked and i could see them printing.
another thing i tried we to debug in VScode but when i click on the next arrow it stay where it is and never gets in the if statement line.
A cursory glance of the simpy
documentation suggests that it operates based on some form of event-based system, it needs hints to know when to wait and for how long via timeout. Generally speaking though, a while True
loop in Python, even for a generator, will simply have an exclusive hold the thread until a yield
is encountered. Since you have no yield
as the alternative option (i.e. in an else
block), the thread will hold until a valid condition is matched to generate a yield
.
A quick fix of your issue (of no feedback) is to simply add the following:
if (len(order_queue.items) > 0) and ...: # other conditions omitted
... # existing code omitted
else:
yield env.timeout(1)
Which will ensure that control is passed back to simpy
so that it can continue the work it was doing. A better method would be to calculate roughly the exact timeout that you need, e.g. timeout until the next order's incoming time.
Moreover, this process_orders
function effectively acts as a "co-routine" - this explanation largely summarizes what this means, and applying that explanation clearly shows that if the function never yield
in a timely manner, no transfer control back to the calling function will happen (which would be simpy
never be able to update/provide feedback/do anything).