我想实现离散事件维护调度模拟,其中一些维护活动必须在另一个维护活动发生时发生。
例如,如果墙壁每5年重新粉刷一次,并且每14年更换一次干衬里,那么每当更换干衬里并重新开始计时时,必须重新粉刷墙壁。
yr 5: paint walls
yr 10: paint walls
yr 14: replace dry-lining
yr 14: paint walls
yr 19: paint walls
...
我不确定是否应该将每个活动实现为引用依赖过程的过程,或者“墙维护”应该是内部处理逻辑的过程,还是其他方式。
我所拥有的代码将每个活动作为一个进程,将依赖进程存储为属性,但我觉得我可能错过了正确的方法,因为我看到事件在同一年发生了两次。 / p>
答案 0 :(得分:1)
你应该总是从一个非常简单(和错误)的实现开始,只是为了更好地理解你的用例和感觉如何工作,例如:
import simpy
def paint_walls(env, interval):
while True:
yield env.timeout(interval)
print('yr %2d: paint walls' % env.now)
def replace_dry_lining(env, interval):
while True:
yield env.timeout(interval)
print('yr %d: replace dry-lining' % env.now)
env = simpy.Environment()
env.process(paint_walls(env, interval=5))
env.process(replace_dry_lining(env, interval=14))
env.run(until=20)
输出:
yr 5: paint walls
yr 10: paint walls
yr 14: replace dry-lining
yr 15: paint walls
然后您可以开始扩展/修改模拟。以下是您可以如何建模问题的两种可能性:
变体A
我们继续使用两个独立的流程,但需要一种方法来交换它们之间的“干衬里更换”事件,这样我们也可以画墙:
import simpy
class Maintenance:
PAINT_WALL_INTERVAL = 5
REPLACE_DRY_LINING_INTERVAL= 14
def __init__(self, env):
self.env = env
self.dry_lining_replaced = env.event()
self.p_paint_walls = env.process(self.paint_walls())
self.p_replace_dry_lining = env.process(self.replace_dry_lining())
def paint_walls(self):
timeout = self.PAINT_WALL_INTERVAL
while True:
yield self.env.timeout(timeout) | self.dry_lining_replaced
print('yr %2d: paint walls' % self.env.now)
def replace_dry_lining(self):
timeout = self.REPLACE_DRY_LINING_INTERVAL
while True:
yield self.env.timeout(timeout)
print('yr %2d: replace dry-lining' % self.env.now)
self.dry_lining_replaced.succeed()
self.dry_lining_replaced = self.env.event()
env = simpy.Environment()
m = Maintenance(env)
env.run(until=20)
输出:
yr 5: paint walls
yr 10: paint walls
yr 14: replace dry-lining
yr 14: paint walls
yr 19: paint walls
变体B
我们也可以通过一个等待“油漆墙”或“替换干衬”事件的过程对其进行建模:
import simpy
def maintenance(env):
PAINT_WALL_INTERVAL = 5
REPLACE_DRY_LINING_INTERVAL = 14
paint_wall = env.timeout(PAINT_WALL_INTERVAL)
replace_dry_lining = env.timeout(REPLACE_DRY_LINING_INTERVAL)
while True:
results = yield paint_wall | replace_dry_lining
do_paint = paint_wall in results
do_replace = replace_dry_lining in results
if do_replace:
print('yr %2d: replace dry-lining' % env.now)
replace_dry_lining = env.timeout(REPLACE_DRY_LINING_INTERVAL)
if do_paint or do_replace:
print('yr %2d: paint walls' % env.now)
paint_wall = env.timeout(PAINT_WALL_INTERVAL)
env = simpy.Environment()
env.process(maintenance(env))
env.run(until=20)
输出:
yr 5: paint walls
yr 10: paint walls
yr 14: replace dry-lining
yr 14: paint walls
yr 19: paint walls
答案 1 :(得分:0)
这是我最终采用的方法:
import simpy
from simpy.events import Interrupt
class Construction(object):
def __init__(self, name, components):
self.name = name
self.components = components
self.link_components()
def link_components(self):
"""Link each component to the next outermost component
"""
for i, component in enumerate(self.components):
try:
component.dependent = self.components[i+1]
except IndexError:
component.dependent = None
class Component(object):
def __init__(self, env, name, lifespan):
"""Represents a component used in a construction.
"""
self.env = env
self.name = name
self.lifespan = lifespan
self.action = env.process(self.run())
def run(self):
while True:
try:
yield self.env.timeout(self.lifespan)
self.replace()
except Interrupt: # don't replace
pass
def replace(self):
print "yr %d: replace %s" % (env.now, self.name)
if self.dependent:
self.dependent.action.interrupt() # stop the dependent process
self.dependent.replace() # replace the dependent component
env = simpy.Environment()
components = [Component(env, 'structure', 60),
Component(env, 'dry-lining', 14),
Component(env, 'paint', 5)]
wall = Construction('wall', components)
env.run(until=65)