Simulating a system of resource with set-up/switch-on times using Simpy
Posted By: Anonymous
I would like to create a system with servers which need time to set-up before being ready to serve. Since the number of servers changes over time, I think Container resource might work. A server is set up whenever there is a customer arriving to the queue, and the the earlier coming customer will seize the server which is ON earlier, like below.
- Customer 1 arrives and requests a server.
- Server 1 is SETUP in t1 secs.
- Customer 2 arrives and requests a server.
- Server 2 is SETUP in t2 secs.
- Server 2 is ON.
- Customer 1 occupies Server 2.
I wonder how I can make the above process actually works. If I arrange the events as below, every loop seems to be stuck after yield req
(Doesn’t yield req
put this request on the queue and fulfill the request as soon as there is a ready server turned on later at yield servers.server.put(1)
?)
with servers.computer.get(1) as req:
yield req
yield env.timeout(switch_on()) #switch on time
yield servers.server.put(1)
"""0.09948 Job0 arrives
0.25648 Job1 arrives
0.37188 Job2 arrives
0.47028 Job3 arrives
0.53916 Job4 arrives
0.66893 Job5 arrives
"""
If I change the order as below, then it would be the case that Customer-i will definitely seize Server-i regardless the order of servers being ON.
with servers.computer.get(1) as req:
yield env.timeout(switch_on()) #switch on time
yield servers.server.put(1)
yield req
Here is the full code.
import simpy
LAM = 8 #arival rate of jobs
MU = 2 #service rate
ALPHA = 12 #set up rate
NUM_SERVERS = 5
MAX_NUM_JOB = 10000000000
UNTIL = 10
def generate_interarrival():
return np.random.exponential(1/LAM)
def generate_service():
return np.random.exponential(1/MU)
def switch_on():
return np.random.exponential(1/ALPHA)
class Generate_Job():
def arriving_job(env, servers):
global num_current_jobs, num_server_on, leaving_time_list
for i in range(MAX_NUM_JOB):
job = Job(name="Job%01d" % (i))
yield env.timeout(generate_interarrival())
print('{0:.5f}'.format(env.now), job.name, "arrives")
env.process(job.handling(env,servers))
class Room: # A room containing servers (resource)
def __init__(self, env):
self.computer = simpy.Container(env, capacity = 10000, init = 0)
class Job(object):
def __init__(self,name):
self.name = name
def handling(self, env, servers):
with servers.computer.get(1) as req:
yield req
yield env.timeout(switch_on()) #switch on time
yield servers.server.put(1)
print('{0:.5f}'.format(env.now), self.name, "occupies a server--")
yield env.timeout(generate_service()) #service time
print('{0:.5f}'.format(env.now), self.name, "leaves")
np.random.seed(0)
env = simpy.Environment()
servers = Room(env)
env.process(Generate_Job.arriving_job(env, servers))
env.run(until = UNTIL)
Solution
Needed to change two things
Your resource pool starts empty, which mean you first request for a resource will wait forever and never get to your code that added a resource.
I added a check before the request that will add a resource if needed. Since there is a delay in adding the resource, the resource request will still have a wait while the resource "starts up". Do not call this check with a yield or the request will wait for the new resource to be added and the request will miss if a resource is added because of another add, or if another job finishes and returns a resource before the new resource is added
Also containers do not return a resource at the end of a "with" statement, only resources do that.
here is the fixed code, let me know what you think
"""
Simulation of a dynamic server pool
Server pool starts empty and servers are added as needed, but there is a delay
simulating start up time before the server is available to fulfill a resource request
Programmer: Matt
Wrote original version
Programmer: Michael R. Gibbs
Added server check for dynamicaly adding servers
Fixed return of resorces to pool
"""
import simpy
import numpy as np
LAM = 8 #arival rate of jobs
MU = 2 #service rate
ALPHA = 12 #set up rate
NUM_SERVERS = 5
MAX_NUM_JOB = 10000000000
UNTIL = 10
def generate_interarrival():
return np.random.exponential(1/LAM)
def generate_service():
return np.random.exponential(1/MU)
def switch_on():
return np.random.exponential(1/ALPHA)
def check_servers(env, servers):
"""
Checks the server pool to see if the pool has any avalable servers
if not then add a server, (there will be a delay before added server becomes available)
Call this without a yield so it does not block if a server is added
"""
print('{0:.5f}'.format(env.now), "checking server pool", "requests:",len(servers.get_queue), "servers:", servers.level)
if len(servers.get_queue) >= servers.level:
# will need another server
d = switch_on()
print('{0:.5f}'.format(env.now), "adding a server at " + '{0:.5f}'.format(env.now + d) + " --")
yield env.timeout(d) #switch on time
yield servers.put(1)
print('{0:.5f}'.format(env.now), "added a server--")
class Generate_Job():
def arriving_job(env, servers):
global num_current_jobs, num_server_on, leaving_time_list
for i in range(MAX_NUM_JOB):
job = Job(name="Job%01d" % (i))
yield env.timeout(generate_interarrival())
print('{0:.5f}'.format(env.now), job.name, "arrives")
env.process(job.handling(env,servers))
class Room: # A room containing servers (resource)
def __init__(self, env):
self.computer = simpy.Container(env, capacity = 10000, init = 0)
class Job(object):
def __init__(self,name):
self.name = name
def handling(self, env, servers):
# added a check to see if a resource pool needs another server.
env.process(check_servers(env,servers.computer))
print('{0:.5f}'.format(env.now), self.name, "requesting a server--")
with servers.computer.get(1) as req:
yield req
# if the queue is empty then the req is never filled and the next lines are never called
# need to do this before the rescource requests
#
# yield env.timeout(switch_on()) #switch on time
# yield servers.server.put(1)
print('{0:.5f}'.format(env.now), self.name, "occupies a server--")
yield env.timeout(generate_service()) #service time
print('{0:.5f}'.format(env.now), self.name, "leaves")
# containers do not return a resouce at the end of a "with"
# added a put
yield servers.computer.put(1)
np.random.seed(0)
env = simpy.Environment()
servers = Room(env)
env.process(Generate_Job.arriving_job(env, servers))
env.run(until = UNTIL)
Answered By: Anonymous
Disclaimer: This content is shared under creative common license cc-by-sa 3.0. It is generated from StackExchange Website Network.