在继续进程的其余部分的同时阻塞多缓冲区系统中的缓冲区

时间:2021-05-23 11:24:54

标签: simpy

我目前正在使用 Simpy,我想模拟一个并行排队系统。有 4 个缓冲区,每个缓冲区存储产品。可以取出一个产品,但缓冲区必须等待 15 分钟才能取出下一个产品。每个缓冲区的容量为 1,但可以在这 15 分钟过去时存储产品。我曾尝试使用 env.timeout(15) 解决此问题,但这会将整个系统超时 15 分钟。如何只阻塞缓冲区,而不阻塞整个系统?

1 个答案:

答案 0 :(得分:0)

您是否通过 yield 调用超时?

我通过使用队列队列 (queueQueue) 然后将获取过程分为三个步骤来做到这一点,从 queueQueue 中拉出队列,然后从队列中拉出 obj。队列在返回到 queueQueue 之前不会再收到任何请求。我等到 obj get 请求被填满(如果队列为空并且需要等待添加 obj,则可能会延迟),然后我对进程进行异步调用(无 yeild)以等待 15 分钟,然后将队列放回 queueQueue。在没有 yield 的情况下调用这个进程可以防止主进程被阻塞。

看看这是否适合你

"""
example where given a pool of queues, once a queue has a get request, block the queue from getting 
furture get requests until 15 minutes after the request is filled.  Note the queue could be empty 
and therefore not fill the request immeditly.  The queue can still get put requests

The two features is a queueQueue which has queue that are ready to process requests.
if a queue is not in the queueQueue it does not get any requests

Second, the process of putting a queue back in the queueQueue is wrapped in a process that can 
be called async (no yield) so it does not block the main process

Programmer: Michael R. Gibbs
"""

import simpy
import random

class Obj():
    """
    dummy object to queue

    has unique IDs
    """
    
    # id counter
    id = 0

    def __init__(self):

        # assign unique id
        Obj.id += 1
        self.id = Obj.id

def getObj(env, queueQueue):
    """
    gets a queue, then gets a obj

    if the queue does not have a obj then will wait until a obj is added to the queue
    once the obj request if filled by the queue the queue is sent to the putQueue process 
    async (no yield) which waits 15 mins before putting the queue in the queueQueue
    """

    # wait for a queue to become available
    queue = yield queueQueue.get()
    print(f'{env.now} queue {queue.id} has been pulled')

    # wait for obj from queue

    obj = yield queue.get()
    print(f'{env.now} obj {obj.id} has been pulled from queue {queue.id}')

    # do not block while watting 15 min (do not use yield here)
    env.process(putQueue( env, queueQueue, queue))

    return obj

def putQueue(env, queueQueue, queue):
    """
    waits 15 minutes and puts a queuue in a queue of queues
    """

    yield env.timeout(15)
    yield queueQueue.put(queue)
    print(f'{env.now} queue {queue.id} has been queued')

def genObj(env, queueList):
    """
    load the queues with objects.
    uses round robin to select queue to add to
    """

    while True:
        # create a obj for the queue and give it a tracking id  
        obj = Obj()
        

        # get the next queue and add obj (queues are filled round robin)
        q = obj.id % 4
        yield queueList[q].put(obj)
        print(f'{env.now} added obj {obj.id} to queue {queueList[q].id}')

        # queue fill rate
        yield env.timeout(random.triangular(10,20,15))
        

def consume(env, id, queueQueue):
    """
    consumer that make queue get requests from the pool of queues
    """

    while True:
        # comsuption rate
        yield env.timeout(random.triangular(10,20,14))
        
        # wraps getting a queue, get a obj from the queue, and queueing the queue
        obj = yield env.process(getObj(env,queueQueue))

        print(f'{env.now} consumer: {id} pulled obj {obj.id}')

env = simpy.Environment()

# the queue of queues
queueQueue = simpy.Store(env, capacity=4)

# the pool of queues with queued obj
queueList = []
for i in range(4):
    queue = simpy.Store(env)
    queue.id = i+1
    queueList.append(queue)
    queueQueue.put(queue)
    print('queue',queue.id)

# start queuing obj (update code to change queue rate)
env.process(genObj(env,queueList))

# start consumming obj (can add more of these)
env.process(consume(env, 1, queueQueue))

env.run(200)
print('done')
相关问题