how to pause the execution of a process if another process starts in simpy

194 Views Asked by At

I'm trying to model a bank's service process (for example) using simpy. However, I would like to insert a lunch break. However, using the interrupt function the call is interrupted and no longer processed and after the interrupt the requests continue to be processed. Is there any way to model this situation in simpy?

class BANCO(object):
  def __init__(self, env, n_caixas, n_prioritario):
    self.env = env
    self.caixa_prioritário = simpy.PriorityResource(env, n_prioritario)
    self.quebrado = False
  
  def tempo_quebra(self, media):
    return random.expovariate(media)

def processo_caixa(env, banco, idade, id):
  #Solicita um caixa
  print('Cliente', id, 'de', idade, 'anos entrou no banco às', env.now)
  # print('Cliente', id, 'de', idade, 'anos solicitou um caixa às', env.now)
  try:
    with banco.caixa_prioritário.request() as caixa:
      yield caixa
      print('Cliente', id, 'de', idade, 'anos começou o atendimento', env.now)
      yield env.timeout(2)
      print('Cliente', id, 'de', idade, 'anos terminou o atendimento', env.now)
      yield env.timeout(0.2)
  except simpy.Interrupt:
    print('caixa indisponível')

def manutencao(env, banco, processo):
  while True:
    yield env.timeout(3)
    if not(banco.quebrado) and processo.is_alive:
      print('Pausa para almoço', env.now)
      banco.quebrado = True
      processo.interrupt()
      yield env.timeout(3)
      print('Fim do almoço', env.now)
      banco.quebrado = False

def rodar(env, n_caixas, n_prioritario):
  banco = BANCO(env, n_caixas, n_prioritario)
  id=1
  while True:
    idade = np.random.triangular(20,35,90)
    processo = env.process(processo_caixa(env, banco, idade, id))
    # print(processo.is_alive)
    env.process(manutencao(env, banco, processo))
    yield env.timeout(np.random.standard_exponential())
    id+=1

N_CAIXAS = 1
N_CAIXAS_PRIORITARIOS = 1
TEMPO_SIMULACO = 40

env = simpy.Environment()
env.process(rodar(env, N_CAIXAS, N_CAIXAS_PRIORITARIOS))
env.run(until = TEMPO_SIMULACO)

output:

Cliente 1 de 37.774686064372275 anos entrou no banco às 0
Cliente 1 de 37.774686064372275 anos começou o atendimento 0
Cliente 2 de 71.29176183444024 anos entrou no banco às 1.5291101832583434
Cliente 1 de 37.774686064372275 anos terminou o atendimento 2
Cliente 2 de 71.29176183444024 anos começou o atendimento 2.2
Cliente 3 de 59.0527016599481 anos entrou no banco às 3.875677459210169
Cliente 2 de 71.29176183444024 anos terminou o atendimento 4.2
Cliente 3 de 59.0527016599481 anos começou o atendimento 4.4
Cliente 4 de 44.81820029628599 anos entrou no banco às 4.609114921062699
Cliente 5 de 29.491494333235128 anos entrou no banco às 5.517706457411619
Cliente 3 de 59.0527016599481 anos terminou o atendimento 6.4
Cliente 4 de 44.81820029628599 anos começou o atendimento 6.6000000000000005
Pausa para almoço 7.609114921062699
caixa indisponível
Cliente 5 de 29.491494333235128 anos começou o atendimento 7.609114921062699
Cliente 6 de 64.40032899103298 anos entrou no banco às 8.131823849558167
Cliente 7 de 43.83187030124143 anos entrou no banco às 8.588000648099568
Cliente 5 de 29.491494333235128 anos terminou o atendimento 9.609114921062698
Cliente 8 de 31.145934836402652 anos entrou no banco às 9.661161527123348
Cliente 6 de 64.40032899103298 anos começou o atendimento 9.809114921062697
Fim do almoço 10.609114921062698
Pausa para almoço 11.131823849558167
caixa indisponível
Cliente 7 de 43.83187030124143 anos começou o atendimento 11.131823849558167
Cliente 9 de 29.453094137468263 anos entrou no banco às 11.23535136907061
Cliente 10 de 39.6830775777505 anos entrou no banco às 11.336456179375972
Cliente 11 de 40.94774693095695 anos entrou no banco às 11.890466361540382
Cliente 7 de 43.83187030124143 anos terminou o atendimento 13.131823849558167
1

There are 1 best solutions below

0
Michael On

Here is one way to do it. I nested lunch inside the main loop so the process could process multiple lunch interrupts. Note I do release the resource during lunch, so there a lag before the process resumes while it waits to seize a new resource.

import simpy
import random
import numpy as np

class BANCO(object):
  def __init__(self, env, n_caixas, n_prioritario):
    self.env = env
    self.caixa_prioritário = simpy.PriorityResource(env, n_prioritario)
    self.quebrado = False
  
  def tempo_quebra(self, media):
    return random.expovariate(media)

def processo_caixa(env, banco, idade, id):
  #Solicita um caixa
  print('Cliente', id, 'de', idade, 'anos entrou no banco às', env.now)
  # print('Cliente', id, 'de', idade, 'anos solicitou um caixa às', env.now)
  
  remaining_proccess_time = 2
  do_lunch = False

  while remaining_proccess_time > 0:

    if do_lunch:
      remaining_lunch_time = 1
      while remaining_lunch_time > 0:
        # need this loop incase there is
        # another lunch inturupt during lunch
        try:
          lunch_start = env.now
          print('Cliente', id, 'de', idade, 'starting lunch', env.now)
          yield env.timeout(remaining_lunch_time)
          print('Cliente', id, 'de', idade, 'finish lunch', env.now)
          remaining_lunch_time = 0
        except simpy.Interrupt:
          # ignore interupt and resume lunch, update remaining lunch time
          print('Cliente', id, 'de', idade, 'lunch interupted', env.now)
          remaining_lunch_time = remaining_lunch_time - (env.now - lunch_start)
      do_lunch = False

    # start processing
    try:
      processing_start = 0
      with banco.caixa_prioritário.request() as caixa:
        yield caixa
        
        processing_start = env.now

        print('Cliente', id, 'de', idade, 'anos começou o atendimento', env.now)
        yield env.timeout(remaining_proccess_time)
        print('Cliente', id, 'de', idade, 'anos terminou o atendimento', env.now)

        remaining_proccess_time = 0

    except simpy.Interrupt:
      print('Cliente', id,'processing interupted for lunch',env.now)
      
      # start lunch
      do_lunch = True

      # update remaing procesing time, if starte
      if processing_start > 0:
        remaining_proccess_time -= (env.now - processing_start)

  print('Cliente', id,'caixa done',env.now)

def manutencao(env, banco, processo):
  while True:
    yield env.timeout(3)
    if not(banco.quebrado) and processo.is_alive:
      print('Pausa para almoço', env.now)
      banco.quebrado = True
      processo.interrupt()
      yield env.timeout(3)
      print('Fim do almoço', env.now)
      banco.quebrado = False

def rodar(env, n_caixas, n_prioritario):
  banco = BANCO(env, n_caixas, n_prioritario)
  id=1
  while True:
    idade = np.random.triangular(20,35,90)
    processo = env.process(processo_caixa(env, banco, idade, id))
    # print(processo.is_alive)
    env.process(manutencao(env, banco, processo))
    yield env.timeout(np.random.standard_exponential())
    id+=1

N_CAIXAS = 1
N_CAIXAS_PRIORITARIOS = 1
TEMPO_SIMULACO = 40

env = simpy.Environment()
env.process(rodar(env, N_CAIXAS, N_CAIXAS_PRIORITARIOS))
env.run(until = TEMPO_SIMULACO)