Sistema de Simulação Simples Go



1. Introdução


A simulação é um método no qual, para realizar experimentos, o sistema real estudado é substituído por um modelo. Nesse modelo, você pode perder as situações individuais e muitas delas. As estatísticas coletadas podem ajudar a tirar conclusões sobre os processos no sistema, bem como traçar caminhos de otimização.

A simulação é frequentemente considerada como uma espécie de testes experimentais, mas, ao mesmo tempo, é menos dispendiosa, permite alterar rapidamente os parâmetros e observar o sistema simulado em dinâmica.

Já há cerca de meio século em modelagem de simulação, modelos de computador foram usados. Muitos programas e estruturas diferentes foram criados para seu desenvolvimento, dentre os quais, na minha opinião, os mais desenvolvidos são as ferramentas para modelagem de sistemas de filas (QS). Um dos programas mais conhecidos e simples para simulação de QS - GPSS World (General Purpose Simulation System - um sistema de modelagem de uso geral), pode ser encontrado em mais detalhes nos links [1] , [2] .

O conceito deste programa foi a base da estrutura de simulação no Go.

Simulação no GPSS


Um modelo no GPSS é uma sequência de blocos (comandos) que descreve os objetos simulados entre os quais as transações estão se movendo. Quando uma transação entra no bloco, são gerados eventos que levam a uma mudança no estado do objeto modelado ou a uma mudança no estado / parâmetros da transação.

Os principais blocos da ordem de dez: GERAR, TERMINAR, ATRIBUIR, APLICAR, LANÇAR, FILA, AVANÇAR, PARTIDA, INÍCIO. Existem cerca de três dúzias de blocos no total. Os blocos possuem parâmetros, que podem ser números, nomes de funções, rótulos no programa de simulação, nomes de variáveis. Mais detalhes sobre os blocos podem ser encontrados, por exemplo, aqui .

Os objetos no GPSS têm um conjunto de atributos numéricos padrão (NAV) e atributos lógicos padrão (ALS). Por exemplo, para uma fila, um dos NAV é o comprimento atual e um exemplo de ALS para alguns equipamentos será VERDADEIRO ou ocupado (FALSO).
Em algumas versões do GPSS, há uma visualização do processo de modelagem, mas na maioria das vezes ele está ausente. Com base nos resultados da simulação, um relatório é gerado no GPSS, indicando o NAV e o ALS para todos os objetos.

Implementação Go


A implementação no Go é o desenvolvimento de um conjunto de objetos em função dos blocos GPSS. O primeiro foi criado Pipeline - o objeto no qual a simulação é realizada.

Com base em um map contém uma lista de componentes para descrever o sistema simulado. Como, durante a simulação, as transações devem passar por uma sequência de blocos em uma ordem estrita, no método de adição de componentes Append , foi implementado o procedimento de inclusão com indicação simultânea dos endereços das transações a partir deles. O nome do componente é usado como chave do map , portanto, cada componente deve ter um nome exclusivo.

Após adicionar todos os componentes, você pode iniciar a simulação usando o método Start . Dentro dele, um desvio cíclico de todos os componentes é implementado por um determinado tempo de simulação. No final da simulação, você pode imprimir um relatório contendo NAV e ALS.

O segundo elemento importante são os componentes reais para descrever a simulação. O seguinte foi implementado: Generator - gera transações, Advance - cria atrasos no caminho da transação, Fila - filas de transações, Facility - um dispositivo que é capturado exclusivamente pela transação por um tempo, Hole - um "buraco" no qual as transações falham no final do caminho. Obviamente, esse conjunto não é suficiente para criar modelos de simulação complexos, mas o suficiente para encontrar a solução e comparar com os resultados do GPSS. Todos os componentes implementam a interface IBaseObj, que cobre a funcionalidade mínima exigida.

Cada componente tem uma fila de transações. Diretamente como uma fila, ele é usado apenas na fila, para outros componentes é apenas um repositório. A fila é implementada com base no map . No processo de modelagem, os componentes passam por sua vez e verificam a prontidão (cumprimento de uma determinada condição) da transação para transmissão ao próximo componente. A transferência é realizada pelo método AppendTransact do próximo componente. Se a transferência for bem-sucedida, a transação será removida da fila, respectivamente, o próximo componente será revezado. Como vários destinatários são definidos para cada componente, se não for possível enviar uma transação para um destinatário, tentamos enviá-la para outro.

Para gerar variáveis ​​aleatórias ao determinar a hora da aparência da transação e criar atrasos, as funções PRNG no Go são usadas.

Como ao modelar, ao mesmo tempo, pode haver muitas transações movendo-se entre diferentes componentes, surgiu a idéia de usar goroutines dentro dos componentes. O pipeline, passando pelos componentes, inicia o manipulador HandleTransacts para cada um deles, dentro do qual a goroutine é criada. Após a conclusão de todas as goroutines, o contador de tempo do modelo é incrementado e o HandleTransacts é chamado HandleTransacts .

O último objeto de chave é a própria transação. Ele tem um identificador, uma hora de nascimento e morte, o proprietário (em qual componente ele está agora), vários parâmetros para calcular o SCA e o SCHL.

Na fig. 1 é um diagrama estrutural da interação dos principais objetos da estrutura durante a modelagem.


Fig. 1. Diagrama estrutural generalizado da interação dos principais objetos na simulação

Exemplo de simulação


Suponha que você precise simular o trabalho de um cabeleireiro. Este é um exemplo famoso do GPSS. Os visitantes vão aleatoriamente, com uma frequência de 18 ± 6 minutos, seu número não é conhecido antecipadamente. Temos um cabeleireiro, ele passa 16 ± 4 minutos em um corte de cabelo. Então, quantas pessoas ele cortará para um dia útil? Quantas pessoas estarão na fila? Qual é o tempo médio necessário para um corte de cabelo e quanto tempo as pessoas esperam na fila? Muitas perguntas e uma simulação simples. O diagrama de blocos na Fig. 2)


Fig. 2. O esquema estrutural de modelar um cabeleireiro

O código para a construção do modelo será o seguinte.

 barbershop := NewPipeline("Barbershop", true) //   clients := NewGenerator("Clients", 18, 6, 0, 0, nil) //   chairs := NewQueue("Chairs") //  master := NewFacility("Master", 16, 4) //  hole := NewHole("Out") //  barbershop.Append(clients, chairs) //       barbershop.Append(chairs, master) //      barbershop.Append(master, hole) //     barbershop.Append(hole) //        barbershop.Start(480) //    <-barbershop.Done //   barbershop.PrintReport() 

Os resultados da simulação podem ser encontrados aqui.
Nome do pipeline "Barbearia"
Tempo de simulação 480
Nome do objeto "Cadeiras"
Conteúdo máximo 1
Total de entradas 26
Zero entradas 11
Entradas zero persistentes 42,31%
Na fila 0
Tempo médio / trans 2,58
Tempo médio / trans sem zero entradas 4,47

Nome do objeto "Clientes"
Gerado 26

Nome do objeto "Mestre"
Avanço médio 16,46
Utilização média 89,17
Entradas numéricas 26.00
Transact 26 na instalação

Nome do objeto "Out"
Morto 25
Avanço médio 16,56
Vida média 19,44

Atendendo a 25 clientes, o dia 26 no momento da conclusão da simulação ainda estava na cadeira do mestre. A fila não passava de uma pessoa, 11 pessoas não esperaram (passe zero) e imediatamente cortaram o cabelo. Em média, as pessoas passaram 2,58 minutos na fila e, daqueles que estavam esperando (não um passe zero), 4,47 minutos. 89,17% de seu tempo, cabeleireiro, corta intensamente.

Obviamente, se você realizar outra simulação, os resultados serão alterados. Porém, durante uma série de simulações, o nível geral da carga do assistente e o número de clientes atendidos serão visíveis. Uma simulação semelhante no GPSS produz resultados semelhantes.

Outro exemplo Há um escritório, tem 10 funcionários e um banheiro. As pessoas querem ir ao banheiro a cada 90 ± 60 minutos, ir ao banheiro por 5 ± 3 minutos, tomar banho por 15 ± 10 minutos, voltar ao escritório por 5 ± 3 minutos. Realizaremos a simulação por 9 horas (8 horas de trabalho + 1 hora de almoço), na fig. 3 é um diagrama estrutural.


Fig. 3. Diagrama estrutural do modelo de emprego do banheiro: à esquerda com um banheiro, à direita com dois

À esquerda é um modelo com um banheiro, à direita com dois. A seguir está o código do modelo.

 waterclosetsim := NewPipeline("Water Closet Simulation", false) office := NewGenerator("Office", 0, 0, 0, 10, nil) wantToToilet:= NewAdvance("Wanted to use the toilet", 90, 60) pathToWC := NewAdvance("Path to WC", 5, 3) queue := NewQueue("Queue to the WC") pathFromWC := NewAdvance("Path from WC", 5, 3) wc := NewFacility("WC", 15, 10) pathToOffice:= NewAdvance("Path from WC", 5, 3) waterclosetsim.Append(office, wantToToilet) waterclosetsim.Append(wantToToilet, pathToWC) waterclosetsim.Append(pathToWC, queue) waterclosetsim.Append(queue, wc) waterclosetsim.Append(wc, pathFromWC) waterclosetsim.Append(pathFromWC, wantToToilet) waterclosetsim.Start(540) <-waterclosetsim.Done waterclosetsim.PrintReport() 

Os resultados da simulação são os seguintes.
Nome do pipeline "Simulação de armário de água"
Tempo de simulação 540
Nome do objeto "Office"
Gerado 10

Nome do objeto "Caminho do WC"
Avanço médio 5,77

Nome do objeto "Caminho para o WC"
Avanço médio 5,22

Nome do objeto "Fila no banheiro"
Conteúdo máximo 4
Total de entradas 36
Zero entradas 8
Zero de entradas persistentes 22,22%
Conteúdos atuais 4
Conteúdo médio 1,78
Tempo médio / trans 24,11
Tempo médio / trans sem zero entradas 31,00

Nome do objeto "WC"
Avanço médio 14,69
Utilização média 87,04
Entradas numéricas 32.00
Transacionar 2 na instalação

Nome do objeto "Queria usar o banheiro"
Avanço médio 95,85

Havia até 4 pessoas na fila, 8 vezes que uma pessoa entrou imediatamente no banheiro, durante o dia útil o banheiro foi usado em 87,04%. O mais significativo, na minha opinião, é que as pessoas esperam cerca de meia hora (31 minutos) na fila do banheiro. Talvez isso se deva ao fato de haver apenas um banheiro, e talvez pelo fato de que, em média, as pessoas ficam nele por 14,69 minutos.

Depois de adicionar outro banheiro, vi que a fila foi reduzida para 3 pessoas, 29 vezes as pessoas imediatamente entraram no banheiro. Mas o mais importante, a expectativa diminuiu quase três vezes.

Conclusão


A estrutura criada no joelho é bastante simples e ainda limitada. Planeja aumentar sua funcionalidade ao nível do GPSS. O valor prático da estrutura é a capacidade de montar rápida e facilmente um modelo de simulação no Go e obter resultados.

O código é publicado no GitHub .

Source: https://habr.com/ru/post/pt448076/


All Articles