队列和中断的Simpy模拟
Simpy Simulation of queue and interruption
我正在尝试使用 Simpy 的 PreemptiveResource 来模拟一个队列。服务器重复以下循环。在每个周期中,服务器运行 0.09 个单位的时间,服务器将关闭 0.01 个单位的时间。如果服务器关闭时服务器当前正在为客户服务,则客户将立即离开。服务恢复后,将为下一位排队的顾客提供服务。但是我的输出好像是客户打断后不会离开。有人可以解释如何解决这个问题吗?非常感谢。
import numpy as np
import simpy
def arrival(lmbda):
i=0
while True:
inter_arrival=-1/lmbda*np.log(np.random.rand())
yield env.timeout(inter_arrival)
i+=1
s1=env.process(service(i))
env.process(shutdown(i,s1))
print(i,"arrival", env.now)
def shutdown(i,s1):
while True:
#########the server is functional for 0.09 units of time
yield env.timeout(0.09)
#########if customer still in the queue
if rqt_list[i-1].processed==False:
s1.interrupt()
else:
return
def service(i ):
###########requesting the server
rqt=desk.request()
rqt_list.append(rqt)
print(i, "request", env.now)
while True:
try:
yield rqt
break
except simpy.Interrupt:
#########leave [delete request from the queue]
rqt.cancel()
print(i, "server shuts down", env.now)
#########the server will shut down for 0.01 units of time
yield env.timeout(0.01)
#return, generate a new request
rqt=desk.request()
rqt_list[i-1]=rqt
print(i, "start the service", env.now)
yield env.timeout(0.2)
print(i, "end the service", env.now)
desk.release(rqt)
env=simpy.Environment()
env.process(arrival(lmbda=7))
rqt_list=[]
desk=simpy.PreemptiveResource(env)
T=1
env.run(until=T)
我没有使用中断。相反,当服务器状态变为非活动状态时,我使用了一个事件来发出信号。然后服务延迟产生于服务时间超时或服务器状态更改事件,以先到者为准。我认为这使客户更清洁客户不需要任何尝试/除外。如果服务因服务器不活动而中断,如果客户需要执行特殊操作,客户仍然可以检查服务器的状态。
代码如下:
"""
example of a server with breaks
programmer: Michael R. Gibbs
"""
import simpy
import numpy as np
class Server():
"""
Provides service to customers, but the service ends if the server goes on break
"""
def __init__(self, env, serverId):
self.env = env
self.serverId = serverId
self.state = "Active" # is ther server Active or Inactive
self.stateChange = self.env.event() # event to yeild on for when server state changes (go on/off break)
self.activeTime = 0.9
self.inactiveTime = 0.1
self.serviceTime = 0.2
# start the server
env.process(self.lifeLoop())
def lifeLoop(self):
"""
Manages that state of the server (Active or Inactive)
also uses a event to braodcast when the state changes
"""
while True:
# active state
yield env.timeout(self.activeTime)
print(self.env.now, f"server {self.serverId} is becoming inactive")
self.state = "Inactive"
# use event to braodcast state has change
oldEvent = self.stateChange
self.stateChange = self.env.event()
oldEvent.succeed()
# inactive state
yield env.timeout(0.1)
print(self.env.now, f"server {self.serverId} is becoming active")
self.state = "Active"
# use event to bradcast state has changed
oldEvent = self.stateChange
self.stateChange = self.env.event()
oldEvent.succeed()
def service(self):
"""
The service delay
ends when service time is up, or if the server becomes inactive
"""
yield env.any_of([self.stateChange, env.timeout(self.serviceTime)])
class ServiceDesk():
"""
Manages the queue for getting a server
"""
def __init__(self, env, serverCnt=2):
self.env = env
self.serverQ = simpy.Store(env, capacity=serverCnt)
# create the servers and add to the queue
for i in range(serverCnt):
server = Server(env,i+1)
self.serverQ.put(server)
def getServer(self):
"""
Gets a server
Servers can become inactive waitting in the queue
only return "Active" servers
"""
server = None
# keep searching the queue until a "Active" server is found
while server is None:
server = yield self.serverQ.get()
if server.state == "Active":
return server
else:
# to prevent a infinate loop, cache inative server in a break process
env.process(self.serverBreak(server))
server = None
def serverBreak(self, server):
"""
Wait for server to become "Active" before putting in back into the queue
"""
yield server.stateChange
self.freeServer(server)
def freeServer(self, server):
"""
puts the server back into the queue
"""
self.serverQ.put(server)
def customer(env, customerId, serviceDesk):
"""
Customer arrives
gets server
gets service from server
returns server
leaves
"""
# arrives
print(env.now, f"customer {customerId} has arrived")
# gets server
server = yield env.process(serviceDesk.getServer())
print(env.now, f"customer {customerId} got server {server.serverId}")
# gets service
yield env.process(server.service())
print(env.now, f"customer {customerId} server {server.serverId} finished service")
# return server
serviceDesk.freeServer(server)
# leaves
print(env.now, f"customer {customerId} has left")
def genCustomers(env, lmbda, serviceDest):
"""
generates the arrival of customers
"""
i=0 # customer id
while True:
inter_arrival=-1/lmbda*np.log(np.random.rand())
yield env.timeout(inter_arrival)
i+=1
env.process(customer(env, i, serviceDesk))
# start the simulation
env=simpy.Environment()
serviceDesk = ServiceDesk(env)
env.process(genCustomers(env,7,serviceDesk))
env.run(5)
我正在尝试使用 Simpy 的 PreemptiveResource 来模拟一个队列。服务器重复以下循环。在每个周期中,服务器运行 0.09 个单位的时间,服务器将关闭 0.01 个单位的时间。如果服务器关闭时服务器当前正在为客户服务,则客户将立即离开。服务恢复后,将为下一位排队的顾客提供服务。但是我的输出好像是客户打断后不会离开。有人可以解释如何解决这个问题吗?非常感谢。
import numpy as np
import simpy
def arrival(lmbda):
i=0
while True:
inter_arrival=-1/lmbda*np.log(np.random.rand())
yield env.timeout(inter_arrival)
i+=1
s1=env.process(service(i))
env.process(shutdown(i,s1))
print(i,"arrival", env.now)
def shutdown(i,s1):
while True:
#########the server is functional for 0.09 units of time
yield env.timeout(0.09)
#########if customer still in the queue
if rqt_list[i-1].processed==False:
s1.interrupt()
else:
return
def service(i ):
###########requesting the server
rqt=desk.request()
rqt_list.append(rqt)
print(i, "request", env.now)
while True:
try:
yield rqt
break
except simpy.Interrupt:
#########leave [delete request from the queue]
rqt.cancel()
print(i, "server shuts down", env.now)
#########the server will shut down for 0.01 units of time
yield env.timeout(0.01)
#return, generate a new request
rqt=desk.request()
rqt_list[i-1]=rqt
print(i, "start the service", env.now)
yield env.timeout(0.2)
print(i, "end the service", env.now)
desk.release(rqt)
env=simpy.Environment()
env.process(arrival(lmbda=7))
rqt_list=[]
desk=simpy.PreemptiveResource(env)
T=1
env.run(until=T)
我没有使用中断。相反,当服务器状态变为非活动状态时,我使用了一个事件来发出信号。然后服务延迟产生于服务时间超时或服务器状态更改事件,以先到者为准。我认为这使客户更清洁客户不需要任何尝试/除外。如果服务因服务器不活动而中断,如果客户需要执行特殊操作,客户仍然可以检查服务器的状态。
代码如下:
"""
example of a server with breaks
programmer: Michael R. Gibbs
"""
import simpy
import numpy as np
class Server():
"""
Provides service to customers, but the service ends if the server goes on break
"""
def __init__(self, env, serverId):
self.env = env
self.serverId = serverId
self.state = "Active" # is ther server Active or Inactive
self.stateChange = self.env.event() # event to yeild on for when server state changes (go on/off break)
self.activeTime = 0.9
self.inactiveTime = 0.1
self.serviceTime = 0.2
# start the server
env.process(self.lifeLoop())
def lifeLoop(self):
"""
Manages that state of the server (Active or Inactive)
also uses a event to braodcast when the state changes
"""
while True:
# active state
yield env.timeout(self.activeTime)
print(self.env.now, f"server {self.serverId} is becoming inactive")
self.state = "Inactive"
# use event to braodcast state has change
oldEvent = self.stateChange
self.stateChange = self.env.event()
oldEvent.succeed()
# inactive state
yield env.timeout(0.1)
print(self.env.now, f"server {self.serverId} is becoming active")
self.state = "Active"
# use event to bradcast state has changed
oldEvent = self.stateChange
self.stateChange = self.env.event()
oldEvent.succeed()
def service(self):
"""
The service delay
ends when service time is up, or if the server becomes inactive
"""
yield env.any_of([self.stateChange, env.timeout(self.serviceTime)])
class ServiceDesk():
"""
Manages the queue for getting a server
"""
def __init__(self, env, serverCnt=2):
self.env = env
self.serverQ = simpy.Store(env, capacity=serverCnt)
# create the servers and add to the queue
for i in range(serverCnt):
server = Server(env,i+1)
self.serverQ.put(server)
def getServer(self):
"""
Gets a server
Servers can become inactive waitting in the queue
only return "Active" servers
"""
server = None
# keep searching the queue until a "Active" server is found
while server is None:
server = yield self.serverQ.get()
if server.state == "Active":
return server
else:
# to prevent a infinate loop, cache inative server in a break process
env.process(self.serverBreak(server))
server = None
def serverBreak(self, server):
"""
Wait for server to become "Active" before putting in back into the queue
"""
yield server.stateChange
self.freeServer(server)
def freeServer(self, server):
"""
puts the server back into the queue
"""
self.serverQ.put(server)
def customer(env, customerId, serviceDesk):
"""
Customer arrives
gets server
gets service from server
returns server
leaves
"""
# arrives
print(env.now, f"customer {customerId} has arrived")
# gets server
server = yield env.process(serviceDesk.getServer())
print(env.now, f"customer {customerId} got server {server.serverId}")
# gets service
yield env.process(server.service())
print(env.now, f"customer {customerId} server {server.serverId} finished service")
# return server
serviceDesk.freeServer(server)
# leaves
print(env.now, f"customer {customerId} has left")
def genCustomers(env, lmbda, serviceDest):
"""
generates the arrival of customers
"""
i=0 # customer id
while True:
inter_arrival=-1/lmbda*np.log(np.random.rand())
yield env.timeout(inter_arrival)
i+=1
env.process(customer(env, i, serviceDesk))
# start the simulation
env=simpy.Environment()
serviceDesk = ServiceDesk(env)
env.process(genCustomers(env,7,serviceDesk))
env.run(5)