问题描述
我正在尝试使用 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,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)