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()