Симуляция метро Simpy: как исправить сбой прерывания классного поезда во время ожидания в очереди за ресурсом?

Я работаю над симуляцией поезда в simpy и до сих пор добился успеха с одним объектом поезда, следуя приведенному ниже коду.

Процессы поездов - это секции, за которыми следуют платформы. Каждая секция и платформа имеют ресурс 1, чтобы гарантировать, что только один поезд будет использоваться одновременно.

Однако я не могу найти способ обойти ошибку ниже:

Когда я добавляю в симуляцию второй поезд, иногда возникает ситуация, когда один поезд ожидает недоступный ресурс, а затем в этом поезде происходит сбой, пока он ожидает.

Я получаю сообщение об ошибке Interrupt: Interrupt().

Есть ли способ обойти эти сбойные очереди для ресурсов?

Любая помощь горячо приветствуется.

import random
import simpy
import numpy

# Configure parameters for the model
RANDOM_SEED = random.seed() # makes results repeatable

T_MEAN_SECTION = 200.0 # journey time (seconds)

DWELL_TIME = 30.0 # dwell time mean (seconds)
DWELL_TIME_EXPO = 1/DWELL_TIME # for exponential distribution

MTTF = 600.0  # mean time to failure (seconds)
TTF_MEAN = 1/MTTF # for exponential distribution

REPAIR_TIME = 120.0 # mean repair time for when failure occurs (seconds)
REPAIR_TIME_EXPO = 1/REPAIR_TIME # for exponential distribution

NUM_TRAINS = 2 # number of trains to simulate

SIM_TIME_HOURS = 1 # sim time in hours
SIM_TIME_DAYS = SIM_TIME_HOURS/18.0 # number of days to simulate
SIM_TIME = 3600 * 18 * SIM_TIME_DAYS # sim time in seconds (this is used in the code below)


# Defining the times for processes
def Section(): # returns processing time for platform 7 Waterloo to 26 Bank
    return T_MEAN_SECTION

def Dwell(): # returns processing time for platform 25 Bank to platform 7 Waterloo
    return random.expovariate(DWELL_TIME_EXPO)

def time_to_failure(): # returns time until next failure
    return random.expovariate(TTF_MEAN)



# Defining the train
class Train(object):

    def __init__(self, env, name, repair):
        self.env = env
        self.name = name
        self.trips_complete = 0
        self.num_saf = 0
        self.sum_saf = 0
        self.broken = False

    # Start "running" and "downtime_train" processes for the train
        self.process = env.process(self.running(repair))
        env.process(self.downtime_train())  


    def running(self, repair):

        while True:

            # request section A
            request_SA = sectionA.request()

########## SIM ERROR IF FAILURE OCCURS HERE ###########
            yield request_SA

            done_in_SA = Section()          
            while done_in_SA:

                try:
                    # going on the trip
                    start = self.env.now


                    print('%s leaving platform at time %d') % (self.name, env.now)

                    # processing time
                    yield self.env.timeout(done_in_SA)

                    # releasing the section resource
                    sectionA.release(request_SA)
                    done_in_SA = 0 # Set to 0 to exit while loop

                except simpy.Interrupt:
                    self.broken = True
                    delay = random.expovariate(REPAIR_TIME_EXPO)
                    print('Oh no! Something has caused a delay of %d seconds to %s at time %d') % (delay, self.name, env.now)
                    done_in_SA -= self.env.now - start # How much time left?
                    with repair.request(priority = 1) as request_D_SA:
                        yield request_D_SA
                        yield self.env.timeout(delay)
                    self.broken = False
                    print('Okay all good now, failure fixed on %s at time %d') % (self.name, env.now)
                    self.num_saf += 1
                    self.sum_saf += delay



            # request platform A
            request_PA = platformA.request()

########## SIM ERROR IF FAILURE OCCURS HERE ###########
            yield request_PA

            done_in_PA = Dwell()
            while done_in_PA:

                try:

                    # platform process
                    start = self.env.now


                    print('%s arriving to platform A and opening doors at time %d') % (self.name, env.now)
                    yield self.env.timeout(done_in_PA)
                    print('%s closing doors, ready to depart platform A at %d\n') % (self.name, env.now)
                    # releasing the platform resource
                    platformA.release(request_PA)
                    done_in_PA = 0 # Set to 0 to exit while loop

                except simpy.Interrupt:
                    self.broken = True
                    delay = random.expovariate(REPAIR_TIME_EXPO)
                    print('Oh no! Something has caused a delay of %d seconds to %s at time %d') % (delay, self.name, env.now)
                    done_in_PA -= self.env.now - start # How much time left?
                    with repair.request(priority = 1) as request_D_PA:
                        yield request_D_PA
                        yield self.env.timeout(delay)
                    self.broken = False
                    print('Okay all good now, failure fixed on %s at time %d') % (self.name, env.now)
                    self.num_saf += 1
                    self.sum_saf += delay


        # Round trip is finished

            self.trips_complete += 1


# Defining the failure event        
    def downtime_train(self):
        while True:
            yield self.env.timeout(time_to_failure())
            if not self.broken:
            # Only break the train if it is currently working
                self.process.interrupt()



# Setup and start the simulation
print('Train trip simulator')
random.seed(RANDOM_SEED) # Helps with reproduction

# Create an environment and start setup process
env = simpy.Environment()

# Defining resources 
platformA = simpy.Resource(env, capacity = 1)
sectionA = simpy.Resource(env, capacity = 1)

repair = simpy.PreemptiveResource(env, capacity = 10)

trains = [Train(env, 'Train %d' % i, repair)
    for i in range(NUM_TRAINS)]


# Execute
env.run(until = SIM_TIME)

person bobo    schedule 05.02.2015    source источник


Ответы (1)


Ваши процессы запрашивают ресурс и никогда его не освобождают. Вот почему второй поезд вечно ждет, пока его запрос не увенчается успехом. Пока он ждет, кажется, что процесс сбоя прерывает процесс. Вот почему вы получаете ошибку. Прочтите руководство по ресурсам, чтобы понять, как работают ресурсы SimPy и, особенно , как освободить ресурс, когда вы закончите.

person Stefan Scherfke    schedule 05.02.2015
comment
Спасибо за ответ Стефан. Однако ресурс освобождается в части while try: ниже, где он запрашивается. Кажется, это работает нормально, так как поезда прекрасно обходят два процесса в цикле... до тех пор, пока не произойдет сбой в одном из поездов, если он стоит в очереди за ресурсом. - person bobo; 05.02.2015
comment
Хорошо, теперь я вижу, где вы публикуете запросы. Проблема по-прежнему заключается в том, что поезд, ожидающий request_SA или request_PA, прерывается процессом сбоя. Например, вы можете обернуть yield request_SA try ... except simpy.Interrupt: pass, чтобы игнорировать его. - person Stefan Scherfke; 06.02.2015