Home > Net >  Problem in simulating a preemptive M/M/1 queue in Python
Problem in simulating a preemptive M/M/1 queue in Python

Time:11-15

The following shows my code which simulates a M/M/1 preemptive queue with two types of arrivals where the first type has priority over the second type. However, I don't know why in my code the preemptive rule is not working the way it should. I mean in a preemptive queue if for example a job of type 2 is receiving service and a job of type 1 arrives, the server interrupts the service for the type 2 job and begins the service for the type 1 job. However, once the service for the type 1 job is done it should continue the service for the interrupted type 2 job.

In my code, if a job type 2 is receiving service and a job type 1 arrives the job type 2 immediately leaves the system permanently. I was wondering if you can tell me why this happens and how I can fix it?

Really appreciate your time and effort in advance.

import random
import simpy

rn_seed = 10
t1_interval_arrivals = 20.0
t2_interval_arrivals = 1
t1_interval_service = 5
t2_interval_service = 20


def type_1_generator(env, interval, server):
    i = 0
    while True:
        c = job(env, "type_1" " #"  str(i), "type_1", server, t1_interval_service)
        env.process(c)
        t = random.expovariate(1.0 / interval)
        yield env.timeout(t)
        i  =1
        
def type_2_generator(env, interval, server):
    i = 0
    while True:
        c = job(env, "type_2" " #" str(i), "type_2", server, t2_interval_service)
        env.process(c)
        t = random.expovariate(1.0 / interval)
        yield env.timeout(t)
        i  =1


def job(env, name, typ , server, sr_interval):

    arrive = env.now
    print("Job", name, "Arrived at: ",arrive)
    service_interval = random.expovariate(1.0 / sr_interval)
    print("Job", name, "Service time: ",service_interval)
    if typ == "type_1":
        while service_interval:
            with server.request(priority=1) as req:
                yield req  
                yield env.timeout(service_interval)
                service_interval = 0
                print("Job", name, "Left system at: ",env.now)
    elif typ == "type_2":
        while service_interval:
            try:
                start = env.now 
                with server.request(priority=2) as req:
                    yield req  
                    yield env.timeout(service_interval)
                    service_interval = 0
                    print("Job", name, "Left system at: ",env.now)
            except simpy.Interrupt:
                print("Job", name, "Is interrupted at: ",env.now)
                service_interval -= env.now - start
                print("Job", name, "Remaining service: ",env.now)
            print("Job", name, "Left system at ",env.now)
            
        


# Setup and start the simulation
random.seed(rn_seed)
env = simpy.Environment()

# Start processes and run
server = simpy.PreemptiveResource(env, capacity=1)
env.process(type_1_generator(env, t1_interval_arrivals, server))
env.process(type_2_generator(env, t2_interval_arrivals, server))
env.run()

Here is a sample of the results:

Job type_2 #1 Arrived at:  0.5601717881563535
Job type_2 #1 Service time:  34.69876113045603
Job type_1 #1 Arrived at:  16.94474499667717
Job type_1 #1 Service time:  0.22635015810062187
Job type_2 #1 Is interrupted at:  16.94474499667717
Job type_2 #1 Remaining service:  18.31418792193521
Job type_2 #1 Left system at  16.94474499667717
Job type_1 #1 Left system at:  17.17109515477779

In the results above you can see that once "Job type_1 #1" arrived at 16.94 the server interrupted service for "Job type_2 #1" and the remaining service time for this job is 18.31. However, once server is done with "Job type_1 #1" it never continues the service for "Job type_2 #1". In fact, "Job type_2 #1" immediately left the system when "Job type_1 #1" arrived. This clearly shows what is my problem with my code. Why "Job type_2 #1" leaves the system immediately and the server never continues the service for this job?

CodePudding user response:

I made a couple of changes to your code. On thing to note is when you resubmit a request for a resource it is put at the end of the queue. So I gave interrupted type two jobs a higher priority then new type two jobs. Type one jobs still have the highest priority. I also added some more print statements.

import random
import simpy

rn_seed = 10
t1_interval_arrivals = 20.0
t2_interval_arrivals = 1
t1_interval_service = 5
t2_interval_service = 20

# use for unique id across all jobs
i = 0

def type_1_generator(env, interval, server):
    
    global i

    while i < 6:
        c = job(env, "type_1" " #"  str(i), "type_1", server, t1_interval_service)
        i  =1
        env.process(c)
        t = random.expovariate(1.0 / interval)
        yield env.timeout(t)
        
def type_2_generator(env, interval, server):
    global i

    while i < 4:
        c = job(env, "type_2" " #" str(i), "type_2", server, t2_interval_service)
        i  =1
        env.process(c)
        t = random.expovariate(1.0 / interval)
        yield env.timeout(t)


def job(env, name, typ , server, sr_interval):
    """
    use three priorites so interuped jobs can
    take precendence over type 2 jobs that have 
    not started yet

    job priorities are:
    type 1: 1
    type 2: 3
    interupted type 2: 2
    """

    arrive = env.now
    print("Job", name, "Arrived at: ",arrive)
    service_interval = random.expovariate(1.0 / sr_interval)
    print("Job", name, "Service time: ",service_interval)
    if typ == "type_1":
        while service_interval:
            with server.request(priority=1) as req:
                yield req  
                print("Job", name, "seized resource at: ",env.now)
                yield env.timeout(service_interval)
                service_interval = 0
            print("Job", name, "released resource at: ",env.now)
        print("Job", name, "finished at: ",env.now)
    elif typ == "type_2":
        priority=3
        while service_interval:
            try:
                with server.request(priority=priority) as req:
                    yield req
                    start = env.now
                    if priority == 3:
                        print("Job", name, "seized resource at: ",env.now) 
                    else:
                        print("Job", name, "resumed with resource at: ",env.now)
                    yield env.timeout(service_interval)
                    service_interval = 0
                print("Job", name, "released resource at: ",env.now)
            except simpy.Interrupt:
                # up priority to take precenance of not started jobs
                priority=2
                print("Job", name, "Is interrupted at: ",env.now)
                service_interval -= env.now - start
                print("Job", name, "Remaining service: ",service_interval)
        print("Job", name, "finished ",env.now)
            
        


# Setup and start the simulation
random.seed(rn_seed)
env = simpy.Environment()

# Start processes and run
server = simpy.PreemptiveResource(env, capacity=1)
env.process(type_1_generator(env, t1_interval_arrivals, server))
env.process(type_2_generator(env, t2_interval_arrivals, server))
env.run()
  • Related