如何中断或取消 SimPy 超时事件?
How do I interrupt or cancel a SimPy Timeout event?
我想创建一个带有回调的计时器,该回调可以使用 SimPy 中断或重置。如果被打断,我不希望执行回调,如果重置,我希望计时器从 env.now
开始以相同的延迟重新启动。这看起来很简单,最初只需使用 env.timeout
就可以做到。但是,文档说明:
To actually let time pass in a simulation, there is the timeout event. A timeout has two parameters: a delay and an optional value: Timeout(delay, value=None). It triggers itself during its creation and schedules itself at now + delay. Thus, the succeed() and fail() methods cannot be called again and you have to pass the event value to it when you create the timeout.
因为模拟starts触发了,我不能加回调因为你不能调用fail
,我不能打断超时
我考虑过只实现一个等待一个时间步长的进程,如果它被中断或到达它正在等待的 env.now
,则检查一个标志,但这似乎效率低得可怕,如果我有很多定时器(我会的),我担心发电机的数量会压倒模拟。 (超时功能似乎通过在模拟的未来安排自己来工作,这就是为什么你可以拥有大量 运行 的原因)。
所以规范是 - 创建一个在指定时间后触发回调的事件,但可以在该时间发生之前重置或中断。有什么想法吗?
好吧,如果我正确理解了你的问题,你可以做的一件事是创建一个 Timer
class 和一个检查 simpy.Interrupt
的等待方法。您可以实现 stop()
,这样当它被调用时,您也可以调用 interrupt()
。这样,只要先前调用了 interrupt()
,就不会执行回调。重置方法将简单地再次调用 stop()
(中断)和 start()
,从而将操作设置回 running()
并再次调用 wait()
,允许回调在每次执行后再次执行超时直到再次调用中断。
下面是这样一个 Timer
class 的示例实现:
import simpy
class Timer(object):
def __init__(self, env, delay, callback):
self.env = env
self.delay = delay
self.action = None
self.callback = callback
self.running = False
self.canceled = False
def wait(self):
"""
Calls a callback after time has elapsed.
"""
try:
yield self.env.timeout(self.delay)
self.callback()
self.running = False
except simpy.Interrupt as i:
print "Interrupted!"
self.canceled = True
self.running = False
def start(self):
"""
Starts the timer
"""
if not self.running:
self.running = True
self.action = self.env.process(self.wait())
def stop(self):
"""
Stops the timer
"""
if self.running:
self.action.interrupt()
self.action = None
def reset(self):
"""
Interrupts the current timer and restarts.
"""
self.stop()
self.start()
我知道这是一个古老的 SO 问题,但我一直在寻找一个简单的 SimPy Timer
class 就像 (which was very useful!), and had a fix for the issue with reset
pointed out by @bbengfort. The reset
function assumes that interrupt
executes immediately, but this is not the case as explained in the SimPy documentation:
中提供的一样
What process.interrupt() actually does is scheduling an Interruption event for immediate execution.
所以对 self.start
的调用实际上是在 wait
进程被中断之前执行的,这阻止了它启动一个新的 wait
进程。
下面是修改后的版本,重置应该可以正常工作。
import simpy
class Timer(object):
def __init__(self, env, delay, callback):
self.env = env
self.delay = delay
self.action = None
self.callback = callback
def wait(self):
"""
Calls a callback after time has elapsed.
"""
try:
yield self.env.timeout(self.delay)
self.callback()
except simpy.Interrupt:
print("Interrupted!")
def running(self):
"""
Check if timer is running
"""
return self.action is not None and self.action.is_alive
def start(self):
"""
Starts the timer
"""
if not self.running():
self.action = self.env.process(self.wait())
def stop(self):
"""
Stops the timer
"""
if self.running():
self.action.interrupt()
self.action = None
def reset(self):
"""
Interrupts the current timer and restarts.
"""
self.stop()
self.start()
我想创建一个带有回调的计时器,该回调可以使用 SimPy 中断或重置。如果被打断,我不希望执行回调,如果重置,我希望计时器从 env.now
开始以相同的延迟重新启动。这看起来很简单,最初只需使用 env.timeout
就可以做到。但是,文档说明:
To actually let time pass in a simulation, there is the timeout event. A timeout has two parameters: a delay and an optional value: Timeout(delay, value=None). It triggers itself during its creation and schedules itself at now + delay. Thus, the succeed() and fail() methods cannot be called again and you have to pass the event value to it when you create the timeout.
因为模拟starts触发了,我不能加回调因为你不能调用fail
,我不能打断超时
我考虑过只实现一个等待一个时间步长的进程,如果它被中断或到达它正在等待的 env.now
,则检查一个标志,但这似乎效率低得可怕,如果我有很多定时器(我会的),我担心发电机的数量会压倒模拟。 (超时功能似乎通过在模拟的未来安排自己来工作,这就是为什么你可以拥有大量 运行 的原因)。
所以规范是 - 创建一个在指定时间后触发回调的事件,但可以在该时间发生之前重置或中断。有什么想法吗?
好吧,如果我正确理解了你的问题,你可以做的一件事是创建一个 Timer
class 和一个检查 simpy.Interrupt
的等待方法。您可以实现 stop()
,这样当它被调用时,您也可以调用 interrupt()
。这样,只要先前调用了 interrupt()
,就不会执行回调。重置方法将简单地再次调用 stop()
(中断)和 start()
,从而将操作设置回 running()
并再次调用 wait()
,允许回调在每次执行后再次执行超时直到再次调用中断。
下面是这样一个 Timer
class 的示例实现:
import simpy
class Timer(object):
def __init__(self, env, delay, callback):
self.env = env
self.delay = delay
self.action = None
self.callback = callback
self.running = False
self.canceled = False
def wait(self):
"""
Calls a callback after time has elapsed.
"""
try:
yield self.env.timeout(self.delay)
self.callback()
self.running = False
except simpy.Interrupt as i:
print "Interrupted!"
self.canceled = True
self.running = False
def start(self):
"""
Starts the timer
"""
if not self.running:
self.running = True
self.action = self.env.process(self.wait())
def stop(self):
"""
Stops the timer
"""
if self.running:
self.action.interrupt()
self.action = None
def reset(self):
"""
Interrupts the current timer and restarts.
"""
self.stop()
self.start()
我知道这是一个古老的 SO 问题,但我一直在寻找一个简单的 SimPy Timer
class 就像 reset
pointed out by @bbengfort. The reset
function assumes that interrupt
executes immediately, but this is not the case as explained in the SimPy documentation:
What process.interrupt() actually does is scheduling an Interruption event for immediate execution.
所以对 self.start
的调用实际上是在 wait
进程被中断之前执行的,这阻止了它启动一个新的 wait
进程。
下面是修改后的版本,重置应该可以正常工作。
import simpy
class Timer(object):
def __init__(self, env, delay, callback):
self.env = env
self.delay = delay
self.action = None
self.callback = callback
def wait(self):
"""
Calls a callback after time has elapsed.
"""
try:
yield self.env.timeout(self.delay)
self.callback()
except simpy.Interrupt:
print("Interrupted!")
def running(self):
"""
Check if timer is running
"""
return self.action is not None and self.action.is_alive
def start(self):
"""
Starts the timer
"""
if not self.running():
self.action = self.env.process(self.wait())
def stop(self):
"""
Stops the timer
"""
if self.running():
self.action.interrupt()
self.action = None
def reset(self):
"""
Interrupts the current timer and restarts.
"""
self.stop()
self.start()