代码之家  ›  专栏  ›  技术社区  ›  bbengfort

如何中断或取消SimPy超时事件?

  •  3
  • bbengfort  · 技术社区  · 10 年前

    我想创建一个带有回调的计时器,该回调可以使用SimPy中断或重置。如果中断,我不希望执行回调,如果重置,我希望计时器以相同的延迟重新启动 env.now 。这似乎是一件简单的事情,最初只需使用 env.timeout 。然而,文件说明:

    为了在模拟中真正让时间过去,存在超时事件。超时有两个参数:延迟和可选值:timeout(delay,value=None)。它在创建过程中自动触发,并在现在+延迟时自动调度。因此,无法再次调用succeed()和fail()方法,您必须在创建超时时将事件值传递给它。

    因为模拟 开始 触发,我无法添加回调,因为您无法调用 fail ,我不能中断超时。

    我考虑过只实现一个进程,它等待一个时间步,并检查标志是否被中断或到达 当前环境 它一直在等待,但这似乎非常低效,如果我有很多计时器(我会),我担心发电机的数量会超过模拟。(超时功能似乎可以通过在模拟的未来调度自己来工作,这就是为什么你可以有大量的时间在运行)。

    因此,规范是-创建一个事件,该事件在指定时间后触发回调,但可以在该时间发生之前重置或中断。有什么想法吗?

    2 回复  |  直到 10 年前
        1
  •  2
  •   kxirog    10 年前

    如果我正确理解了你的问题,你可以做的一件事就是创建一个 Timer 使用检查 simpy.Interrupt .你可以 stop() 所以当它被调用时,你也会调用 interrupt() 。这样,只要 中断() 之前已调用。重置方法只需调用 停止() (中断)和 start() 再次将操作设置为 running() 和呼叫 wait() 同样,允许在每次超时后再次执行回调,直到再次调用中断。

    下面是这样一个示例实现 计时器 类别:

    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()
    
        2
  •  1
  •   svnesbo    4 年前

    我知道这是一个古老的SO问题,但我正在寻找一个简单的SimPy Timer 类,就像中提供的 @kxirog's answer (这非常有用!),并解决了问题 reset @bbengfort指出。这个 重置 函数假定 interrupt 立即执行,但情况并非如 SimPy documentation :

    什么过程。interrupt()实际上是调度一个interrupt事件以便立即执行。

    因此 self.start 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()