Desafio 4: imprima na tela o tempo de simulação e o números de clientes em fila. Quantos clientes existem em fila no instante 4.5?
Para solução do desafio, basta lembrarmos que a qualquer momento, o conjunto de entidades em fila pelo recurso é dado por servidorRes.queue e, portanto, o número de entidade em fila é facilmente obtido pela expressão:
len(servidorRes.queue)
Foi acrescentada uma chamadas à função print, de modo a imprimir na tela o número de clientes em fila ao término do atendimento de cada cliente:
defatendimentoServidor(env,nome,servidorRes):# função que ocupa o servidor e realiza o atendimento # solicita o recurso servidorRes request = servidorRes.request()# aguarda em fila até a liberação do recurso e o ocupayield request print('%.1f Servidor inicia o atendimento do %s'% (env.now, nome))# aguarda um tempo de atendimento exponencialmente distribuídoyield env.timeout(random.expovariate(1.0/TEMPO_MEDIO_ATENDIMENTO))print('%.1f Servidor termina o atendimento do %s. Clientes em fila: %i'% (env.now, nome, len(servidorRes.queue)))# libera o recurso servidorResyield servidorRes.release(request)
Executado o código, descobrimos que no instante 5,5 min, temos 2 clientes em fila:
0.5 Chegada do cliente 10.5 Servidor inicia o atendimento do cliente 11.4 Servidor termina o atendimento do cliente 1. Clientes em fila:03.1 Chegada do cliente 23.1 Servidor inicia o atendimento do cliente 23.3 Chegada do cliente 34.1 Servidor termina o atendimento do cliente 2. Clientes em fila:14.1 Servidor inicia o atendimento do cliente 34.1 Servidor termina o atendimento do cliente 3. Clientes em fila:04.3 Chegada do cliente 44.3 Servidor inicia o atendimento do cliente 44.5 Servidor termina o atendimento do cliente 4. Clientes em fila:0
Portanto, existem 0 cliente em fila no instante 4,5 minutos, nas condições simuladas (note a semente de geração de números aleatórios igual a 2).
Desafio 5: calcule o tempo de permanência em fila de cada cliente e imprima o resultado na tela. Para isso, armazene o instante de chegada do cliente na fila em uma variável chegada.
Ao final do atendimento, armazene o tempo de fila, numa variável tempoFila e apresente o resultado na tela.
A ideia deste desafio é que você se acostume com esse cálculo tão trivial quanto importante dentro da simulação: o tempo de permanência de uma entidade em algum local. Neste caso, o local é uma fila por ocupação de um recurso.
A lógica aqui é a de um cronometrista que deve disparar o cronômetro na chegada do cliente e pará-lo ao início do atendimento.
Assim, ao chegar, criamos uma variável chegada que armazena o instante atual fornecido pelo comando env.now do SimPy:
defatendimentoServidor(env,nome,servidorRes):# função que ocupa o servidor e realiza o atendimento# armazena o instante de chegada do cliente chegada = env.now # solicita o recurso servidorRes request = servidorRes.request()
Agora, inciado o atendimento (logo após o yield que ocupa o recurso), a variável tempoFila armazena o tempo de permanência em fila. Como num cronômetro, o tempo em fila é calculado pelo instante atual do cronômetro menos o instante de disparo dele já armazenado na variável chegada:
defatendimentoServidor(env,nome,servidorRes):# função que ocupa o servidor e realiza o atendimento# armazena o instante de chegada do cliente chegada = env.now # solicita o recurso servidorRes request = servidorRes.request()# aguarda em fila até a liberação do recurso e o ocupayield request# calcula o tempo em fila tempoFila = env.now - chegada
Para imprimir o resultado, basta simplesmente alterar a chamada à função print na linha seguinte, de modo que o código final da função atendimentoServidor
fica:
defatendimentoServidor(env,nome,servidorRes):# função que ocupa o servidor e realiza o atendimento# armazena o instante de chegada do cliente chegada = env.now # solicita o recurso servidorRes request = servidorRes.request()# aguarda em fila até a liberação do recurso e o ocupayield request# calcula o tempo em fila tempoFila = env.now - chegada print('%.1f Servidor inicia o atendimento do %s. Tempo em fila: %.1f'% (env.now, nome, tempoFila))# aguarda um tempo de atendimento exponencialmente distribuídoyield env.timeout(random.expovariate(1.0/TEMPO_MEDIO_ATENDIMENTO))print('%.1f Servidor termina o atendimento do %s. Clientes em fila: %i'% (env.now, nome, len(servidorRes.queue)))# libera o recurso servidorResyield servidorRes.release(request)
Agora, a execução do programa mostra na tela o tempo de espera de cada cliente:
0.5 Chegada do cliente 10.5 Servidor inicia o atendimento do cliente 1. Tempo em fila:0.01.4 Servidor termina o atendimento do cliente 1. Clientes em fila:03.1 Chegada do cliente 23.1 Servidor inicia o atendimento do cliente 2. Tempo em fila:0.03.3 Chegada do cliente 34.1 Servidor termina o atendimento do cliente 2. Clientes em fila:14.1 Servidor inicia o atendimento do cliente 3. Tempo em fila:0.84.1 Servidor termina o atendimento do cliente 3. Clientes em fila:04.3 Chegada do cliente 44.3 Servidor inicia o atendimento do cliente 4. Tempo em fila:0.04.5 Servidor termina o atendimento do cliente 4. Clientes em fila:0
Desafio 6: um problema clássico de simulação envolve ocupar e desocupar recursos na seqüência correta. Considere uma lavanderia com 4 lavadoras, 3 secadoras e 5 cestos de roupas. Quando um cliente chega, ele coloca as roupas em uma máquina de lavar (ou aguarda em fila). A lavagem consome 20 minutos (constante). Ao terminar a lavagem, o cliente retira as roupas da máquina e coloca em um cesto e leva o cesto com suas roupas até a secadora, num processo que leva de 1 a 4 minutos distribuídos uniformemente. O cliente então descarrega as roupas do cesto diretamente para a secadora, espera a secagem e vai embora. Esse processo leva entre 9 e 12 minutos, uniformemente distribuídos. Construa um modelo que represente o sistema descrito.
A dificuldade do desafio da lavanderia é representar corretamente a sequência de ocupação e desocupação dos recursos necessários de cada cliente. Se você ocupá-los/desocupá-los na ordem errada, fatalmente seu programa apresentará resultados inesperados.
Como se trata de um modelo com vários processos e distribuições, vamos seguir a Dica da seção "Solução dos desafios 2 e 3" e construir uma função para armazenar as distribuições do problema, organizando nosso código:
import randomimport simpydefdistributions(tipo):# função que armazena as distribuições utilizadas no modeloreturn{'chegadas': random.expovariate(1.0/5.0),'lavar':20,'carregar': random.uniform(1, 4),'descarregar': random.uniform(1, 2),'secar': random.uniform(9, 12),}.get(tipo, 0.0)
Como já destacado, a dificuldade é representar a sequência correta de processos do cliente: ele chega, ocupa uma lavadora, lava, ocupa um cesto, libera uma lavadora, ocupa uma secadora, libera o cesto, seca e libera a secadora. Se a sequência foi bem compreendida, a máscara a seguir será de fácil preenchimento:
import randomimport simpycontaClientes =0# conta clientes que chegaram no sistemadefdistributions(tipo):# função que armazena as distribuições utilizadas no modeloreturn{'chegadas': random.expovariate(1.0/5.0),'lavar':20,'carregar': random.uniform(1, 4),'descarregar': random.uniform(1, 2),'secar': random.uniform(9, 12),}.get(tipo, 0.0)defchegadaClientes(env,lavadoras,cestos,secadoras):# função que gera a chegada de clientesglobal contaClientespass# chamada do processo de lavagem e secagempassdeflavaSeca(env,cliente,lavadoras,cestos,secadoras):# função que processa a operação de cada cliente dentro da lavanderia# ocupa a lavadorapass# antes de retirar da lavadora, pega um cestopass# libera a lavadora, mas não o cestopass# ocupa a secadora antes de liberar o cestopass# libera o cesto mas não a secadorapass# pode liberar a secadorapassrandom.seed(10)env = simpy.Environment()lavadoras = simpy.Resource(env, capacity =3)cestos = simpy.Resource(env, capacity =2)secadoras = simpy.Resource(env, capacity =1)env.process(chegadaClientes(env, lavadoras, cestos, secadoras))env.run(until =40)
O programa a seguir apresenta uma possível solução para o desafio, já com diversos comandos de impressão:
import randomimport simpycontaClientes =0# conta clientes que chegaram no sistemadefdistributions(tipo):# função que armazena as distribuições utilizadas no modeloreturn{'chegadas': random.expovariate(1.0/5.0),'lavar':20,'carregar': random.uniform(1, 4),'descarregar': random.uniform(1, 2),'secar': random.uniform(9, 12),}.get(tipo, 0.0)defchegadaClientes(env,lavadoras,cestos,secadoras):# função que gera a chegada de clientesglobal contaClientes contaClientes =0whileTrue: contaClientes +=1yield env.timeout(distributions('chegadas'))print("%.1f chegada do cliente %s"%(env.now, contaClientes))# chamada do processo de lavagem e secagem env.process(lavaSeca(env, "Cliente %s"% contaClientes, lavadoras, cestos, secadoras))deflavaSeca(env,cliente,lavadoras,cestos,secadoras):# função que processa a operação de cada cliente dentro da lavanderiaglobal utilLavadora, tempoEsperaLavadora, contaLavadora# ocupa a lavadora req1 = lavadoras.request()yield req1print("%.1f%s ocupa lavadora"%(env.now, cliente))yield env.timeout(distributions('lavar'))# antes de retirar da lavadora, pega um cesto req2 = cestos.request()yield req2print("%.1f%s ocupa cesto"%(env.now, cliente))yield env.timeout(distributions('carregar'))# libera a lavadora, mas não o cesto lavadoras.release(req1)print("%.1f%s desocupa lavadora"%(env.now, cliente))# ocupa a secadora antes de liberar o cesto req3 = secadoras.request()yield req3print("%.1f%s ocupa secadora"%(env.now, cliente))yield env.timeout(distributions('descarregar'))# libera o cesto mas não a secadora cestos.release(req2)print("%.1f%s desocupa cesto"%(env.now, cliente))yield env.timeout(distributions('secar'))# pode liberar a secadoraprint("%.1f%s desocupa secadora"%(env.now, cliente)) secadoras.release(req3)random.seed(10)env = simpy.Environment()lavadoras = simpy.Resource(env, capacity=3)cestos = simpy.Resource(env, capacity=2)secadoras = simpy.Resource(env, capacity=1)env.process(chegadaClientes(env, lavadoras, cestos, secadoras))env.run(until=40)
A execução do programa anterior fornece como saída:
A fila M/M/1 possui expressões analíticas conhecidas. Por exemplo, o tempo médio de permanência no sistema é dado pela expressão: W=μ−λ1. Valide seu modelo, ou seja, calcule o resultado esperado para a expressão e compare com o resultado obtido pelo seu programa.
No problema da lavanderia, crie uma situação de desistência, isto é: caso a fila de espera por lavadoras seja de 5 clientes, o próximo cliente a chegar no sistema desiste imediatamente de entrar na lavanderia.