python transition lib - 在从单一状态转换之前等待多个事件?

时间:2017-08-04 20:57:38

标签: python transitions fsm

来自github问题https://github.com/pytransitions/transitions/issues/247的交叉发布。

我使用python的过渡FSM库,我需要等待3件事情发生才能转换到下一个状态。

State = WAIT_FOR_3_THINGS
Events = thing_1_done, thing_2_done, thing_3_done

事件_ * _事件可以按任何顺序排列,所以我更愿意避免使用:

thing_1_and_2_donething_1_and_3_donething_2_and_3_done

我可以跟踪事件,1,2和& 3并提前

conditions=[thing_1_and_2_done, thing_1_and_3_done, thing_2_and_3_done]

但我不确定最佳聚合这些事件的位置。

是否有更多的skookum(ok,pythonic)这样做?

3 个答案:

答案 0 :(得分:1)

在转换到下一个状态之前,使用一个集合来定义我想要累积的事件列表。

例如:

curl --digest -u admin:passwd.123 -L -D - http://localhost:9990/management \
  --header "Content-Type: application/json" \
  -d '{"operation":"whoami","verbose":"true","json.pretty":1}'

将实例变量添加到FSM实例以跟踪在进入“空闲”状态时被清除的实例:

deps_required = {'got_thing_1', 'got_thing_2', 'got_thing_3'}

然后,在条件子句中聚合并检查事件子类型:

self.run_deps_set = set()

不觉得超级吱吱干净,但我不讨厌(太多)。

答案 1 :(得分:1)

从务实的角度来看,solution是转换的方式,imho。对于这样的问题,并发状态机可能值得一看。

对于这种特殊情况,这肯定是在顶部,但我想借此机会展示转换如何处理并发。 更确切地说,我们可以使用它处理多个模型来实现并发的能力。 在下面的示例中,我扩展了Machine a)一个方法来触发所有模型上的事件,b)使用一种方法初始化工人模型并将实际模型存储在内部变量中(虽然这不是一个合适的堆栈)。 使用ignore_invalid_triggers时,每个工作程序都会等待相应的事件,并在完成时将自己从ParallelMachine模型列表中删除。当模型列表为空时,ParallelMachine将再次恢复实际的模型状态。

from transitions import Machine


class WorkerModel:

    def __init__(self, machine):
        self.machine = machine

    # I show myself out when I am done
    def on_enter_Done(self):
        self.machine.remove_model(self)


class ParallelMachine(Machine):

    def __init__(self, *args, **kwargs):
        self._pushed_models = []
        super(ParallelMachine, self).__init__(*args, **kwargs)

    # save actual models and initialise worker tasks
    def add_worker(self, tasks):
        self._pushed_models = self.models
        self.models = []
        for t in tasks:
            self.add_model(WorkerModel(self), initial=t)

    # trigger an event on ALL models (either workers or actual models)
    def trigger(self, trigger, *args, **kwargs):
        for m in self.models:
            getattr(m, trigger)(*args, **kwargs)
        if not self.models:
            self.models = self._pushed_models
            self._pushed_models = []
            for m in self.models:
                getattr(m, trigger)(*args, **kwargs)


class Model:

    def __init__(self):
        # the state list contains model states as well as worker states
        states = ['Idle', 'Processing', 'Done', 'need_1', 'need_2', 'need_3']
        # potentially got_1/2/3 all can trigger a transition to 'Done'
        # but the model will only be triggered when the worker list
        # has been emptied before
        transitions = [['process', 'Idle', 'Processing'],
                       ['got_1', ['Processing', 'need_1'], 'Done'],
                       ['got_2', ['Processing', 'need_2'], 'Done'],
                       ['got_3', ['Processing', 'need_3'], 'Done']]
        # assigning machine to a model attribute prevents the need
        # to pass it around
        self.machine = ParallelMachine(model=self, states=states,
                                       transitions=transitions, initial='Idle',
                                       ignore_invalid_triggers=True)

    def on_enter_Processing(self):
        self.machine.add_worker(['need_1', 'need_2', 'need_3'])

    def on_enter_Done(self):
        print("I am done")


model = Model()
machine = model.machine
assert model.state == 'Idle'
# we use ParallelMachine.trigger instead of model.<event_name>
machine.trigger('process')
assert model.state == 'Processing'
machine.trigger('got_3')
machine.trigger('got_1')
# duplicated events do not matter
machine.trigger('got_3')
assert model.state == 'Processing'
machine.trigger('got_2')
# worker stack was empty and 
assert model.state == 'Done'

这样全局状态可能是&#34;处理(need_1 / need_2 / done)&#34;或者&#34;处理(完成/需要_ /完成)&#34;无需明确建模所有变体。

并发在transitions待办事项列表中,但需要进行一些更改。例如,预计所有模型都可以使用回调(例如,从on_enter_Done删除Model将引发异常)。

答案 2 :(得分:0)

不知道这是一个伟大的,甚至是好的解决方案,但你可以考虑将每个东西作为一个函数进行线程化或多处理,并在每个东西的末尾包含一个var,当它完成时翻转为真。

然后一个简单的如果a-complete,b-complete,c-complete bools-are-true check应该可以让你到达目的地。