Search code examples
pythonif-statementsimulationsimpy

if statement under a simulation infinite while loop pauses the whole program


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.


Solution

  • 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).