繁体   English   中英

Model 单个活动需要不同的资源类型

[英]Model single activity requiring different resource types

进程 3 需要资源 A 和 B,并且只能在进程 1(由资源 A)和进程 2(由资源 B)完成后启动。 下面的代码似乎按预期执行,但 if / else 语句看起来很不优雅。 是否有“更好”的方式来完成相同的行为?

def orchestration(self):
    # Request resources A and B
    req_resourceA = self.resourceA.request()
    req_resourceB = self.resourceB.request()

    # Wait until first resource is available (will change throughout simulation)
    available_rec = yield.self.env.any_of([req_resourceA, req_resourceB])

    if list(available_rec.keys())[0] == resourceA:
        proc1 = self.env.process(self.process1())
        yield resourceB
        proc2 = self.env.process(self.process2())
    else:
        proc2 = self.env.process(self.process2())
        yield resourceA
        proc1 = self.env.process(self.process1())
  
    # Start process 3 only after processes 1 and 2 have been completed
    yield proc1 & proc2
    yield self.env.timeout(process3_time)

    # Manually release both resource requests
    self.resourceA.release(req_resourceA)
    self.resourceB.release(req_resourceB)

在此解决方案中,我并行而不是按顺序运行进程 1 和 2,并使用 all_of 等待两个进程完成。 这应该会减少资源的一些空闲时间。 进程 1 和 2 也获取它们需要的资源,但不释放它。 相反,他们返回请求,以便将其传递给进程 3。我将资源请求传递给进程 3,认为进程 3 会知道何时释放每个资源。 例如进程 3 可以释放资源 A,做更多的事情,然后释放资源 B

"""
One way steps can be sequcenced

In this example the pre steps are run in parallel 
rather the sequentially

Programmer: Michael R. Gibbs
"""

from urllib import request
import simpy
import random

def process1(env, resPool):
    """
    Simple process that grabs a resource and does some processing

    The resource request is not released, but returned to the calling process
    """

    resRequest = resPool.request()

    yield resRequest

    print(f'{env.now:0.2f} process 1 has resource and started')

    yield env.timeout(random.randint(1,5))

    print(f'{env.now:0.2f} process 1 has finish')

    return resRequest
    
def process2(env, resPool):
    """
    another simple process that grabs a resource and does some processing

    The resource request is not released, but returned to the calling process
    """

    resRequest = resPool.request()

    yield resRequest

    print(f'{env.now:0.2f} process 2 has resource and started')

    yield env.timeout(random.randint(1,5))

    print(f'{env.now:0.2f} process 2 has finish')

    return resRequest

def process3(env, resourceAPool, requestA, resourceBPool, requestB):
    """
    Final process that reuses resouces from process1 and process2
    which this process is dependant on
    """

    print(f'{env.now:0.2f} process 3 started')

    yield env.timeout(random.randint(1,5))

    resourceAPool.release(requestA)
    resourceBPool.release(requestB)

    print(f'{env.now:0.2f} process 3 finish')

def endToEndProcessing(env, resourceAPool, resourceBPool):
    """
        the end to end processes
        where process1 and process2 must complete before process 3 can start
    """

    while True:
        # start each pre process, but do not yeild so they runn in parallel
        proc1 = env.process(process1(env,resourceAPool))
        proc2 = env.process(process2(env,resourceBPool))

        # wait for both processes to finish
        preProcesses = yield env.all_of([proc1, proc2])

        # get resource requests and pass to process 3
        reqA = preProcesses[proc1]
        reqB = preProcesses[proc2]

        yield env.process(process3(env, resourceAPool, reqA, resourceBPool, reqB))


env = env = simpy.Environment()
resourceAPool = simpy.Resource(env, capacity=1)
resourceBPool = simpy.Resource(env, capacity=1)

env.process(endToEndProcessing(env, resourceAPool, resourceBPool))

env.run(100)

这是一个更复杂的答案

这里每个进程都是异步运行的,使用资源和存储来控制进程的运行。 这里的优点是您可以拥有多个进程,并且通过控制每个进程的数量,您可以进行一些负载平衡。

基本流程是进程 1 和 2 获取资源,通过 2 个存储将资源传递给进程 3,资源 A 存储 1,资源 B 存储 1。进程 3 完成后释放资源

"""
One way steps can be sequenced

In this example the all the processes are run asyc
using a couple of stores to control when process 3 can run 

The advanatage to this is allows for load balancing.

For example if process1 takes twice as long as process2
and process2 takes twice as long as process3, then
best resource use might be with 4 process1's 2 process2's and 1 process3

Programmer: Michael R. Gibbs
"""

from urllib import request
import simpy
import random

process3Cnt = 0

def process1(env, id, resPool, reqStore):
    """
    Simple process that grabs a resource and does some processing

    The resource request is not released, but returned to a store
    which process 3 uses to know when it can start
    """

    while True:
        resRequest = resPool.request()

        yield resRequest

        print(f'{env.now:0.2f} process 1 id:{id} has resource and started')

        yield env.timeout(random.randint(1,16))

        reqStore.put(resRequest)

        print(f'{env.now:0.2f} process 1 id:{id} has finish')

def process2(env, id, resPool, reqStore):
    """
    Another Simple process that grabs a resource and does some processing

    The resource request is not released, but returned to a store
    which process 3 uses to know when it can start
    """

    while True:
        resRequest = resPool.request()

        yield resRequest

        print(f'{env.now:0.2f} process 2 id:{id} has resource and started')

        yield env.timeout(random.randint(1,8))

        reqStore.put(resRequest)

        print(f'{env.now:0.2f} process 2 id:{id} has finish')

    
def process3(env, id, resourceAPool, requestAStore, resourceBPool, requestBStore):
    """
    Final process that reuses resouces from process1 and process2
    which this process is dependant on

    The resouce requests are passed to proccess 3 using stores
    """

    global process3Cnt

    while True:

        storeAReq = requestAStore.get()
        storeBReq = requestBStore.get()

        # wait for both store request to finish
        storeRequests = yield env.all_of([storeAReq, storeBReq])

        # get the resource requests
        requestA = storeRequests[storeAReq]
        requestB = storeRequests[storeBReq]

        print(f'{env.now:0.2f} process 3 id:{id} started')

        yield env.timeout(random.randint(1,4))

        # release the resources
        resourceAPool.release(requestA)
        resourceBPool.release(requestB)

        print(f'{env.now:0.2f} process 3 id:{id} finish')

        process3Cnt += 1


env = env = simpy.Environment()
resourceAPool = simpy.Resource(env, capacity=4)
resourceBPool = simpy.Resource(env, capacity=2)

requestAStore = simpy.Store(env)
requestBStore = simpy.Store(env)


# try changing the number of each process to maximize the throughput 

#launch process1
for id in range(1,5):
    env.process(process1(env, id, resourceAPool, requestAStore))

#launch process2
for id in range(1,3):
    env.process(process2(env, id, resourceBPool, requestBStore))

#launch process3
for id in range(1,2):
    env.process(process3(env, id, resourceAPool, requestAStore, resourceBPool, requestBStore))

env.run(100)

print(f'Process 3 ran {process3Cnt} times')

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM