使用回调开始简单模拟 运行

Starting a simpy simulation run using a callback

如何从回调中编写一些模拟代码(包括等待事件)?

将我的过程简化为最简单的示例,我想在我的简单模拟中发生事件时启动一些可执行代码。我所做的是将该可执行代码设置为事件的回调。该可执行代码本身有一些简单的事件处理,特别是超时。在我的真实代码中,这发生在一个进程中,但是这个简化版本,其中 event 在 main 中显示相同的问题行为:

import simpy
if __name__ == '__main__':
    env = simpy.Environment()

    def simulationRun(event):
        print("Starting a run at time [%i]" % env.now)
        yield env.timeout(5)
        print("Ending a run at time [%i]" % env.now)

    event = env.timeout(5)
    event.callbacks.append(simulationRun)

    print("Starting simulation.")
    env.run(20)
    print("End of simulation.")

我的预期输出是:

Starting simulation.
Starting a run at time [5]
Ending a run at time [10]
End of simulation.

然而,我的实际输出是:

Starting simulation.
End of simulation.

当我删除 yield 命令时,我得到:

Starting simulation.
Starting a run at time [5]
Ending a run at time [5]
End of simulation.

显然回调设置正确,但重点是模拟 simulationRun 中的超时。我如何在回调代码中 运行 一些模拟代码(包括等待事件)?

这使用 Python 3.4.2 和 simpy。

问题在于回调不是进程,因此在 simpy 模拟引擎中它不是 运行 可以由引擎停止和重新启动的方式。你需要的是一个过程。您可以通过从单独的回调函数启动该代码来使当前 simulationRun 成为一个进程,如下所示。

import simpy  

if __name__ == '__main__':
    env = simpy.Environment()

    def simulationRun():
        print("Starting a run at time [%i]" % env.now)
        yield env.timeout(5)
        print("Ending a run at time [%i]" % env.now)

    def callback(event):
        s = simulationRun()
        env.process(s)

    event = env.timeout(5)
    event.callbacks.append(callback)

    print("Starting simulation.")
    env.run(20)
    print("End of simulation.")

您不应直接使用回调。最佳做法是使用另一个 为您启动 simulation_run() 的进程:

import simpy


def simulation_run(env):
    print("Starting a run at time [%i]" % env.now)
    yield env.timeout(5)
    print("Ending a run at time [%i]" % env.now)


def starter(env):
    yield env.timeout(5)
    env.process(simulation_run(env))


if __name__ == '__main__':
    env = simpy.Environment()
    env.process(starter(env))
    print("Starting simulation.")
    env.run(20)
    print("End of simulation.")

由于这是一个相对常见的模式,我们在其中内置了一个效用函数 SimPy 正是这样做的:

import simpy
import simpy.util


def simulation_run(env):
    print("Starting a run at time [%i]" % env.now)
    yield env.timeout(5)
    print("Ending a run at time [%i]" % env.now)


if __name__ == '__main__':
    env = simpy.Environment()
    simpy.util.start_delayed(env, simulation_run(env), delay=5)
    print("Starting simulation.")
    env.run(20)
    print("End of simulation.")

注意:您应该始终将对环境的引用传递到您的进程中 而不是使用全局范围内的那个。这可能看起来很乏味,但你 如果您稍后重组或重构您的代码,可以 运行 遇到任何类型的问题 并且全局环境不再是您所期望的或不再可用。