A instância de Process retornada por Environment.process() pode ser usada para interagir com o processo. Environment.process() can be utilized for process interactions. Dois exemplos mais comuns de uso são para aguardar o término de algum outro processo e interromper a execução de outro processo enquanto se espera por um evento.

Esperando por um Processo

Como mencionado, um Process Simpy pode ser usado como um evento ( tecnicamente falando, um processo é um evento). Se você marcá-lo com yield, ele continua uma vez que o processo tenha concluído. Imagine a simulação de uma lava a jato onde os carros entram para a limpeza e aguardam que o processo de lavagem seja concluído. Ou uma simulação de um aeroporto onde os passageiros tem de esperar até que os procedimentos de segurança sejam concluídos.

Vamos assumir que o carro do nosso exemplo anterior, vire do nada um carro elétrico. Carros elétricos geralmente levam muito tempo carregando suas baterias após uma viagem. Eles teriam de esperar até que suas baterias estivessem carregadas para que continuassem sua viagem.

Poderiamos alterar o modelo adicionando ao carro o processo charge(). Antes, é preciso refatorar nossa classe carro para que os processos tenham dois métodos: run() ( o qual antes era a função car() ) e charge().

O processo run é iniciado automaticamente quando Car é instanciado. E um processo charge é chamado toda vez que o carro começa a estacionar. Ao se solicitar uma instância de Process retornado pelo método Environment.process(), o processo run fica aguardando o término do evento:

>>> class Car(object):
...     def __init__(self, env):
...         self.env = env
...         # Start the run process everytime an instance is created.
...         self.action = env.process(self.run())
...
...     def run(self):
...         while True:
...             print('Estacionando e carregando em %d' % self.env.now)
...             charge_duration = 5
...             # We yield the process that process() returns
...             # to wait for it to finish
...             yield self.env.process(self.charge(charge_duration))
...
...             # Ao termino do carregamento então podemos
...             # voltar a dirigir.
...             print('Dirigindo em %d' % self.env.now)
...             trip_duration = 2
...             yield self.env.timeout(trip_duration)
...
...     def charge(self, duration):
...         yield self.env.timeout(duration)

Iniciando a simulação novamente: Nós criamos um ambiente/environment, um ( ou mais ) carros e finalmente chamamos o método run().

>>> import simpy
>>> env = simpy.Environment()
>>> car = Car(env)
>>> env.run(until=15)
Estacionando e carregando em 0
Dirigindo em 5
Estacionando e carregando em 7
Dirigindo em 12
Estacionando e carregando em 14

Interrompendo a execução de outro Processo

Digamos que você não quer aguardar até que o carro elétrico esteja completamente carregado e sim deseja parar o processo de carga para começar a dirigir.

SimPy permite que você interrompa a execução de um processo chamando o método interrupt()

>>> def driver(env, car):
...     yield env.timeout(3)
...     car.action.interrupt()

O processo driver tem uma referência para processo action do carro. Depois de esperar por 3 passos da simulação, ele interrompe aquele processo.

As interrupções são aplicadas nos processos como exceções Interrupt que podem (ou devem) ser tratadas pelo processo que foi interrompido. O processo por sua vez pode então decidir o que fazer em seguida (por exemplo: continuar a esperar o evento que o originou ou iniciar um novo evento):

>>> class Car(object):
...     def __init__(self, env):
...         self.env = env
...         self.action = env.process(self.run())
...
...     def run(self):
...         while True:
...             print('Estacionando e carregando em %d' % self.env.now)
...             charge_duration = 5
...             # Caso seja interrompido enquanto carrega a bateria
...             try:
...                 yield self.env.process(self.charge(charge_duration))
...             except simpy.Interrupt:
...                 # Ao receber a solicitacao de interrupcao do processo
...                 # de carga, nos paramos de carregr e mudamos o estado
...                 # para "dirigindo"/"driving"
...                 print('Interrompido o processo. Espero que a bateria tenha carga suficiente ...')
...             print('Dirigindo em %d' % self.env.now)
...             trip_duration = 2
...             yield self.env.timeout(trip_duration)
...
...     def charge(self, duration):
...         yield self.env.timeout(duration)

Se compararmos as mensagens de saída da simulação anterior com a atual, veremos que o carro agora começa a ser dirigido em 3 ao invés de 5:

>>> env = simpy.Environment()
>>> car = Car(env)
>>> env.process(driver(env, car))
<Process(driver) object at 0x...>
>>> env.run(until=15)
Estacionando e carregando em 0
Interrompido o processo. Espero que a bateria tenha carga suficiente ...
Dirigindo em 3
Estacionando e carregando em 5
Dirigindo em 10
Estacionando e carregando em 12

E agora?

Nós demonstramos apenas dois métodos simples para interação com os processos—esperando por um processo e interrompendo um processo. Dê uma olhada em Topical Guides ou documentação da API Process para maiores detalhes.

Na próxima seção vamos enteder o básico da utilização de recursos compartilhados.