Impulsionar Statechart vs. Meta State Machine

142

Aparentemente, o boost contém duas bibliotecas separadas para máquinas de estado: Statechart e Meta State Machine (MSM). Os slogans dão descrições muito semelhantes:

  • Boost.Statechart - Máquinas de estado finito arbitrariamente complexas podem ser implementadas em código C ++ de fácil leitura e manutenção.
  • Meta State Machine - Uma biblioteca de alto desempenho para máquinas de estado finito UML2 expressivas.

Você sabe quais são as principais diferenças e quais são as considerações na escolha entre as duas?

FireAphis
fonte
4
Hehe, outro caso de lotes de interesse, mas ninguém sabe a resposta ... :)
j_random_hacker
8
: D Esta questão é o auge da minha experiência com SO! Obter respostas de ambos os desenvolvedores ... pode melhorar ?! Muito obrigado a Christophe e Andreas.
FireAphis
Excelente pergunta e você conseguiu obter as respostas dos dois desenvolvedores concorrentes!
Offirmo
3
O Statechart faz com que você coloque funcionalidade em construtores e destruidores. Isso é um anti-padrão, especialmente com destruidores.
Lev
2
No Statechart, as ações de saída podem ser colocadas em um manipulador exit () separado chamado antes da destruição. Penso que esta disposição atenua o principal problema com o antipadrão mencionado por Lev.
Tim Crews

Respostas:

116

Como parece haver muito interesse, permita-me dar minha opinião (obviamente tendenciosa), que deve, portanto, ser tomada com um grão de sal:

  • MSM é muito mais rápido
  • O MSM não requer RTTI nem nada virtual
  • O MSM possui um suporte UML2 mais completo (por exemplo, transições internas, regiões ortogonais em conformidade com UML)
  • O MSM oferece uma linguagem descritiva (na verdade várias). Por exemplo, usando o front-end do eUML, uma transição pode ser descrita como Origem + Evento [Guarda] / Ação == Destino
  • O MSM fará com que seu compilador sofra com máquinas de estado maiores, portanto, você precisará de um compilador bem recente (g ++> = 4.x, VC> = 9)

Você pode ter uma opinião melhor procurando comentários publicados durante a revisão do MSM. Este assunto foi muito discutido na lista de desenvolvedores.

Christophe Henry
fonte
2
Muito obrigado. É uma delícia ouvir a opinião do próprio desenvolvedor! Agora só precisamos da resposta de Andreas Huber :)
FireAphis
16
Nit-pick menor: no modo de liberação, o uso de C ++ RTTI (dynamic_cast, typeid) é estritamente opcional com o Boost.Statechart.
111

Como Christophe já mencionou, uma das principais diferenças entre as duas bibliotecas é o desempenho em tempo de execução. Embora o MSM provavelmente ofereça o melhor que você pode obter aqui, o Statechart troca conscientemente os ciclos de memória e processador para uma melhor escalabilidade.

Com o Boost.Statechart, você pode espalhar o layout (ou seja, estados, transições) da sua máquina de estado por várias unidades de tradução (arquivos cpp) de maneiras que não é possível com o MSM. Isso permite que você torne a implementação de FSMs maiores mais sustentável e obtenha uma compilação muito mais rápida do que com o MSM.

Se a sobrecarga de desempenho do Statechart, comparada ao MSM, será realmente significativa para o seu aplicativo, é bastante fácil responder quando você se pergunta quantos eventos o aplicativo deve processar por segundo.

Supondo que um FSM moderadamente complexo seja implementado com o Boost.Statechart, aqui estão alguns números aproximados:

  • O hardware de PC mais atual suporta facilmente mais de 100.000 eventos por segundo
  • Mesmo um hardware com muita restrição de recursos poderá processar algumas centenas de eventos por segundo.

Em relação à carga da CPU, se o número de eventos a processar for muito menor que esses números, a sobrecarga do Boost.Statechart em comparação com o MSM quase certamente não será perceptível. Se o número for muito maior, você definitivamente estará melhor com o MSM.

Informações mais detalhadas sobre as compensações de desempenho / escalabilidade podem ser encontradas aqui: http://www.boost.org/doc/libs/1_45_0/libs/statechart/doc/performance.html


fonte
9
Oi Andreas, sobre a divulgação do layout, houve algumas melhorias. Agora você pode compilar submáquinas em diferentes núcleos. Não é perfeito, mas uma melhoria notável. Veja svn.boost.org/svn/boost/trunk/libs/msm/doc/HTML/…
Christophe Henry
11

Ao codificar minha própria implementação de PPP, usei o Statechart por três razões: 1) O Statechart é mais simples e possui documentação mais clara; 2) Eu realmente não gosto da UML :)

Os documentos do Boost dizem que o MSM é pelo menos 20 vezes mais rápido, mas é muito lento para o FSM grande.

chama
fonte
7
Embora eu concorde que grande parte da UML é a roupa nova dos imperadores, os gráficos de estado são a única coisa que realmente tem valor na UML.
Jon Trauntvein
4
Definitivamente, mas aprendi gráficos estatísticos com matemática discreta, não com engenharia de software. Isso deixa uma marca :)
chama
4

Algum tempo atrás, comecei com o Statechart e mudei para o MSM porque era mais fácil usar em conjunto com o asio a partir de um único thread. Não consegui mesclar o Statechart e seus recursos de multithreading com o uso do asio - provavelmente era algum tipo de incompreensão de novato do Statechart da minha parte. Eu descobri que o MSM era mais fácil de usar, pois não tratava de multithreading.

carma de aranha
fonte
1
A maioria dos tipos de gráfico de estados também não aborda threading. No que diz respeito ao multithreading, você deve poder usar o boost :: statechart :: state_machine como o equivalente do MSM. boost :: statechart :: asynchronous_state_machine e tipos associados são uma parte estritamente opcional da biblioteca statechart.
2

Em resposta à entrada tardia de Tim na discussão (que também aborda um dos primeiros comentários de Lev).

Como um dos que defenderam a separação de saída dos destruidores no gráfico de estados (argumento baseado em um caso de uso real, sobre a interação com o mundo real, isto é, E / S), quando foi submetido ao Boost, concordo que pode haver problemas para colocar o exit lógica em destruidores. David Abrahams, sem surpresa, também apresentou argumentos persuasivos em relação à segurança de exceções. Por esses motivos, o Statechart não exige que você coloque lógica nos destruidores - mas permite - com os conselhos habituais.

A lógica que só deve ser executada como parte de uma transição para fora de um estado (não a destruição do objeto do gráfico de estados como um todo) pode (e deve, se houver também limpeza de recursos a fazer) ser separada em uma ação exit () separada.

Para um estado "thin" sem estado ativo (recursos), apenas ações de entrada / saída a serem executadas, você pode executar essas ações no ctor e no d'tor e garantir que o construtor e o destruidor não atinjam. Não há motivo para eles - não há estado para executar a RAII - não há mal em fazer com que o tratamento de erros nesses locais crie eventos apropriados. Talvez você ainda precise considerar se deseja que as ações de saída que alteram o estado externo sejam executadas na destruição da máquina de estado ... e as coloque em ação de saída se não desejar que ocorram nesse caso ...

O Statechart modela a ativação como instanciação de um objeto, portanto, se o seu construtor tem trabalho / ativação / instanciação real a fazer e se é capaz de falhar de modo que o estado não possa ser inserido, o Statechart suporta isso, oferecendo a capacidade de mapear uma exceção para um objeto. evento. Isso é tratado de uma maneira que elabore a hierarquia de estados procurando um estado externo que lide com o evento de exceção, análogo ao modo como a pilha teria se desenrolado para um modelo de chamada baseado em pilha de chamadas.

Tudo isso está bem documentado - sugiro que você leia os documentos e tente. Sugiro que você use destruidores para limpar "recursos de software" e sair de ações para executar "ações de saída do mundo real".

Vale notar que a propagação de exceção é um pouco problemática em todos os ambientes controlados por eventos, não apenas nos gráficos de estados. É melhor raciocinar e incluir falhas / erros no design do gráfico de estados e, se e somente se você não puder lidar com eles de outra maneira, recorra ao mapeamento de exceções. Pelo menos isso funciona para mim - ymmmv ....

da77a
fonte
Obrigado, vejo que todas as minhas preocupações são abordadas suficientemente na parte "Manipulação de exceções" do tutorial Boost :: statechart. Nesse caso, acho que o comentário (enganoso) de Lev pode ser abordado simplesmente apontando para a seção "saída em dois estágios" desse tutorial. Eu consideraria excluir minha resposta, exceto que sua própria resposta adiciona informações valiosas a este tópico.
Tim Crews