3

我想创建一个带有回调的计时器,可以使用 SimPy 中断或重置。如果中断,我不希望执行回调,如果重置,我希望计时器以相同的延迟从env.now. 最初只需使用env.timeout. 但是,文档指出:

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

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

我考虑过只实现一个等待一个时间步长并检查标志是否已被中断或到达env.now它正在等待的标志,但这似乎非常低效,如果我有很多计时器(我会这样做),我'我担心生成器的数量会压倒模拟。(超时功能似乎通过在模拟的未来自行安排来工作,这就是为什么你可以让大量的人跑来跑去)。

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

4

2 回答 2

2

好吧,如果我正确理解了您的问题,您可以做的一件事是创建一个Timer带有等待方法的类,该方法检查simpy.Interrupt. 您可以实施stop(),以便在调用时也调用interrupt(). 这样,只要interrupt()之前调用过回调,就不会执行回调。重置方法将简单地调用stop()(中断)并start()再次调用,从而将操作设置回running()并再次调用wait(),允许在每次超时后再次执行回调,直到再次调用中断。

这是此类的示例实现Timer

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()
于 2016-02-09T16:40:04.760 回答
1

我知道这是一个古老的 SO 问题,但我正在寻找一个简单的 SimPyTimer类,就像@kxirog 的答案中提供的那个(这非常有用!),并解决了reset@bbengfort 指出的问题。该reset函数假定interrupt立即执行,但这不是SimPy 文档中解释的情况:

process.interrupt() 实际做的是安排一个中断事件以立即执行。

所以调用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()
于 2022-01-13T17:09:19.703 回答