【问题标题】:Incorrect usage of Simpy resources错误使用 Simpy 资源
【发布时间】:2021-10-13 12:30:44
【问题描述】:

我目前正在尝试使用 Simply 模拟离散事件模拟中的商店。由于我的python知识有限,我遇到了一个问题。商店为他们的客户修理损坏的产品,但是,我的模拟没有按预期工作。我试图在堆栈溢出上找到类似的问题,但我找不到它,所以我问。如果已经解决了类似的问题,能否提供链接?

我正在模拟一家商店,顾客带着损坏的产品到达那里,收银员通过将损坏的产品换成修理好的产品来帮助他们。顾客带着修理好的产品离开,损坏的产品随后在商店里修理。修好后可用于帮助其他客户。

我遇到的问题是我的模拟瓶颈,也就是产品的修复。当请求修理工时,python 立即假定请求的修理工很忙。但是,在我的模拟中,必须满足一些条件才能让修理工开始修理。其中一个条件是必须有维修人员来维修产品,但是由于 python 假定维修人员在请求后很忙,因此由于无法满足条件,因此无法开始该过程。如果我在 while 语句之前不请求修理工,则无法正确记录队列,因此我选择了这种方式。

我提供了我的整个代码中出现问题的精简部分。在提供的代码中,应该修复第三个损坏的产品时会出现问题。这是因为模拟有 3 名维修人员可用。如果我有 8 个维修人员可用,那么第八个损坏的产品就会出现问题。

有没有办法解决或规避我的问题? 提前谢谢你。

import simply
class Store(object):
def __init__(self, env, num_cashiers, num_repairman):
    self.env = env
    
    self.num_cashiers = num_cashiers
    self.num_repairman = num_repairman
    self.cashiers = simpy.Resource(env, capacity=num_cashiers)
    self.repairman = simpy.Resource(env, capacity=num_repairman)
    
    self.total_customers = 0
    self.broken_product = 0
    self.repaired_product = 25
    
    self.resource_data = []
    
    


def customer_generator(self, env):

    customer_buffer = 5
    product_id = 1
    customer_interarrival_time = 100
    
    while True: #always generate customers during simulation

        if len(self.cashiers.queue) >= customer_buffer:     #if customer queue is full, customer is lost
            self.lost_customers +=1
    
        else: #If queue not full, start the process in the store
           
            env.process(self.store_operations(env, product_id))

        yield env.timeout(customer_interarrival_time) #wait for next customer
        product_id+=1
        self.total_customers +=1

def serve_customer(self, product_id):
    
    yield self.env.timeout(90)
    self.broken_product +=1
    self.repaired_product -=1
       
def repair_product(self, product_id):
    
    yield self.env.timeout(300)
    self.broken_product -=1
    self.repaired_product +=1

def store_operations(self, env, product_id):
    '''This function is where the problem persists
    While statement 1 exists the check if there are repaired products and a cashier available to help the customer
    otherwise timeout until both are available
    
    if statement 1 helps the customer by swapping a broken product for a repaired product
    
    while statement 2 exists to check if there are broken product to be repaired and whether a repairman is available
    otherwise timeout until both are available
    
    if statement 2 is where the repairman repairs a broken product'''
    
    # print(env.now, ', RP inv', self.repaired_product, ', BP inv', self.broken_product, ', busy cashiers', self.cashiers.count, ', cashier q', len(self.cashiers.queue))
    request_cashier = self.cashiers.request()
    yield request_cashier
    # print(env.now, ', RP inv', self.repaired_product, ', BP inv', self.broken_product, ', busy cashiers', self.cashiers.count, ', cashier q', len(self.cashiers.queue))
    while self.repaired_product==0 or self.cashiers.count==self.num_cashiers: 
        yield env.timeout(1)
    
    if self.repaired_product>0 and self.cashiers.count<self.num_cashiers:
        # print(env.now, ', RP inv', self.repaired_product, ', BP inv', self.broken_product, ', busy cashiers', self.cashiers.count, ', cashier q', len(self.cashiers.queue))
        yield env.process(self.serve_customer(product_id))
        self.cashiers.release(request_cashier)
        # print(env.now, ', RP inv', self.repaired_product, ', BP inv', self.broken_product, ', busy cashiers', self.cashiers.count, ', cashier q', len(self.cashiers.queue))

    print('product', product_id, 't before req', env.now, ', RP inv', self.repaired_product, ', BP inv', self.broken_product, ', busy repairmen', self.repairman.count, ', cashier q', len(self.repairman.queue))
    request_repair = self.repairman.request()
    yield request_repair                     
    print('product', product_id,'t after req', env.now, ', RP inv', self.repaired_product, ', BP inv', self.broken_product, ', busy repairmen', self.repairman.count, ', cashier q', len(self.repairman.queue))
    
    while self.broken_product==0 or self.repairman.count==self.num_repairman:
        yield env.timeout(1)
        print(env.now,'product', product_id,  'wait for repairman')         
    
    if self.broken_product>0 and self.repairman.count<self.num_repairman:

        print('product', product_id,'t before repair proces', env.now, ', RP inv', self.repaired_product, ', BP inv', self.broken_product, ', busy repairmen', self.repairman.count, ', cashier q', len(self.repairman.queue))
        yield env.process(self.repair_product(product_id))
        self.repairman.release(request_repair)
        print('product', product_id,'t after repair process',env.now, ', RP inv', self.repaired_product, ', BP inv', self.broken_product, ', busy repairmen', self.repairman.count, ', cashier q', len(self.repairman.queue))
    
    self.resource_data.append({
        'time' : env.now,
        'broken product inv' : self.broken_product,
        'repaired product inv': self.repaired_product,
        'busy cashiers' : self.cashiers.count,
        'cashier queue' : len(self.cashiers.queue),
        'busy repairmen' : self.repairman.count,
        'repairmen queue' : len(self.repairman.queue)})
    
    return self.resource_data


    env = simpy.Environment()

    store1 = Store(env, 3, 3)
    env.process(store1.customer_generator(env))


    env.run(500)


    print(store1.resource_data[0])
    print(store1.resource_data[1])
    print(store1.resource_data[2])
    print(store1.resource_data[3])
    print(store1.resource_data[4])
    print(store1.resource_data[5])
    print(store1.resource_data[6])


      

【问题讨论】:

    标签: python simpy


    【解决方案1】:

    我将其分解为两个独立的过程。一个过程是维修工人修理出现在维修队列中的破损灯。另一种是收银员,从顾客那里拿坏灯放入维修队列,从固定队列中分发维修好的灯。所以这显示了两个独立的进程如何使用 Store 来回传递工作

    """
    Quick simulation of a lamp exchange shop
    
    Customer arrives with a broke lamp
    If a repaired lamp is avalable, 
    customer exchnage boken for repaired lamp and leaves
    If a repaired lamp is not avalable, 
    customer drops off boken lamp for repair and gets a raincheck returns later
    
    Customer arrives with a raincheck after dropping of a broken lamp
    if a repaired lamp is availale, customer takes repaired lamp and leaves
    if a repaired lamp is not available customer returns later
    
    When a broken lamp is droped off 
    a resource pool of repair workers repairs the lamp and makes
    the repaired lamp available for exchange
    
    Programmer: Michael R. Gibbs
    """
    
    import simpy
    import random
    
    class Lamp():
        """
        Quick class to collect stats on lamp rapair
        """
    
        lamp_cnt = 0 # used to gnerate unique lamp ids
    
        def __init__(self, state='broken'):
            """
            Init class vars, gen new id
            """
    
            Lamp.lamp_cnt += 1
            self.lamp_id = Lamp.lamp_cnt
            self.state = state # possible states: broken, repaired
    
    class Lamp_Store():
        """
        Models the serving of customers with cashiers
        and the repairing of broken lamps with repair workers
        """
        
        def __init__(self, env, num_cashieres=2, num_repair_workers=3, starting_lamp_stock=2, max_queue_len=5):
            """
            Sets up the resurce pools and stock of repaired lamps
            """
    
            self.env = env
    
            self.max_queue_len = max_queue_len
    
            # cashiers that service customers with lamps
            self.cashiers = simpy.Resource(env, capacity=num_cashieres)
    
            # start repair workers repairing lamps (save for future enchancements)
            self.reqair_workers = [env.process(self.repair_lamps(id + 1)) for id in range(num_repair_workers)]
    
            # stores for broken and repair lamps
            self.broken_lamps = simpy.Store(env)
            self.repaired_lamps = simpy.Store(env)
    
    
            # sead the store of repaired lamps with some lamps
            self.repaired_lamps.items = [Lamp(state='repaired') for _ in range(starting_lamp_stock)]
    
        def customer_arrives(self, customer):
            """
            Start the processing of the customer by
            putting them in a queue for a cashier
            """
    
            if len(self.cashiers.queue) >= self.max_queue_len:
                # line too long, lost customer
                print(f'{self.env.now} customer {customer.customer_id} has arrived queue has {len(self.cashiers.queue)} customers, too long, leaving')
    
            else:
                while customer.lamp is None or customer.lamp.state == 'broken':
                    # still need a repaired lamp
    
                    print(f'{self.env.now} customer {customer.customer_id} has arrived queue has {len(self.cashiers.queue)} customers')
    
                    # chekc queue size
                    if len(self.cashiers.queue) >= self.max_queue_len:
                        # queue too long
                        # come back later
                        print(f'{self.env.now} customer {customer.customer_id} line too long, come back later')
                    else:
                        # get service
                    
                        # still needs a repaired lamp
                        yield self.env.process(self.cashier_serves_customer(customer))
                    
                    if customer.lamp is None or customer.lamp.state == 'broken':
                        # need to come back for lamp
                        yield self.env.timeout(random.randint(5,15))
                        print(f'{self.env.now} customer {customer.customer_id} return to shop')
    
        def cashier_serves_customer(self, customer):
            """
            wait in queue for cashier
            exchange lamp, or get raincheck
            """
    
            # wait for next available cashier
            with self.cashiers.request() as req:
                yield req
    
                # got cashier
                if customer.lamp is not None:
                    #drop off broken lamp
                    yield env.timeout(random.randint(4,10))
                    lamp = customer.lamp
                    self.broken_lamps.put(customer.lamp)
                    customer.lamp = None
                    print(f'{self.env.now} customer {customer.customer_id} dropped off borken lamp {lamp.lamp_id}')
    
                if len(self.repaired_lamps.items) > 0:
                    # have a repaired lamp to exchnge
                    customer.lamp = yield self.repaired_lamps.get()
                    print(f'{self.env.now} customer {customer.customer_id} got repaired lamp {customer.lamp.lamp_id}')
    
                else:
                    # no lamps, rain check
                    customer.has_raincheck = True
    
        def repair_lamps(self, worker_id):
            """
            Models a repair worker wainting for a broken lamp
            and fixing it
            """
    
            while True:
                # wait for next borken lamp
                lamp = yield self.broken_lamps.get()
                print(f'{self.env.now} worker {worker_id} has started to repair lamp {lamp.lamp_id}')
    
                # fix broken lamp
                yield self.env.timeout(int(random.triangular(5,14,15)) + 1)
    
                # make fixed lamp available for exchange
                lamp.state = 'repaired'
    
                self.repaired_lamps.put(lamp)
                print(f'{self.env.now} worker {worker_id} has finished repairing lamp {lamp.lamp_id}')
    
                
    class Customer():
        """
        Customer trying to exchange a broken lamp
        """
        customer_cnt = 0
    
        def __init__(self):
    
            Customer.customer_cnt += 1
            self.customer_id = Customer.customer_cnt
    
            self.lamp = Lamp(state='broken')
    
    def gen_customers(env,store):
        """
        Generate customers with broken lamps and send to store
        """
    
        while True:
            yield env.timeout(random.randint(1,3))
            cust = Customer()
    
            env.process(store.customer_arrives(cust))
    
    
    # boot up the simulation
    env = simpy.Environment()
    store = Lamp_Store(env)    
    
    env.process(gen_customers(env, store))
    
    env.run(200)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-03
      • 1970-01-01
      • 2014-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多