简体   繁体   English

RentalService 的 SimPy 模拟在所有流程的所有收益语句都完成之前停止

[英]SimPy Simulation of RentalService stops before all yield statements of all processes are fulfilled

Multiple identical Items can be "rented" from a SimPy store element.可以从 SimPy 商店元素中“租用”多个相同的项目。 The availability of Items is limited to a number lower than the actual demand.项目的可用性仅限于低于实际需求的数量。 By using yield statements other processes should wait until their demand can be met.通过使用yield语句,其他进程应该等到它们的需求得到满足。 The simulation should run until all processes have finished and returned their items back to the store.模拟应该一直运行,直到所有流程都完成并将其物品退回商店。

The following code runs and behaves as expected as long as the number of items is very large so that every demand can be met at any time.只要项目数量非常多,以下代码就会按预期运行和运行,以便随时满足每个需求。

When the number of items is limited to 4 (as in the code below) no scheduling takes place, no elements from the store are "rented".当项目数量限制为 4 时(如下面的代码所示),不会发生调度,商店中的元素不会被“租用”。 If the processes occur at the same point in time in the simulation both cant "rent" elements from the store如果过程发生在模拟中的同一时间点,则两者都不能从商店“租用”元素

import simpy
import random
from numpy.random import default_rng

rng = default_rng()

# demo arrival array: 3 days with 3 usecases each
arrivals = [3, 3, 3]

# runtime of the simulation
runtime = 200

# store capacity
availability = 4

# demo uscase list
list_of_uscases = [

    {
        "usecase": "eMotorbike",
        "dep_mean": 7,
        "dep_std": 1,
        "num_Batteries": 4},

    {
        "usecase": "eCar",
        "dep_mean": 17,
        "dep_std": 1,
        "num_Batteries": 4},

    {
        "usecase": "eBike",
        "dep_mean": 12,
        "dep_std": 1,
        "num_Batteries": 4,},
]


# function that generates the individual processes = rentals of batteries
def usecase_gen(env):
    # for the number of simulated days do:
    day = 0
    for j in arrivals:
        # for the number of usecases per simulated day do:
        count = 0
        for k in range(j):
            # choose a random uscase from the list for all appearances per day
            n = random.choice(list_of_uscases)

            # add process generator to the process function called "job()"
            env.process(job(env, count, day, n["num_Batteries"], n))
            count += 1
        day += 1

        # make sure that a day has 24h
        yield env.timeout(24)


# main process function for every uscase appearance = rental of MBs
def job(env, count, day, resources_required, n):

    # generate the dummy starting time for a usecase based on the order of appearance
    yield env.timeout(count)

    # create an empty array to store the used resources
    resources_used = []

    print('On day {} Uscase {}_{} requires: {} Batteries at time: {}'.format(day, n["usecase"], count, resources_required,
                                                                       env.now))

    # for every resource in resources_required do:
    for i in range(resources_required):
        # reserve ressources that are passed in the "resources_required" parameter
        i = yield resources.get()

        # append the used resources to the list of used resources
        resources_used.append(i)

    print('On day {} Uscase {}_{} rented: {} Batteries at time: {}'.format(day, n["usecase"], count, resources_required,
                                                                     env.now))
    # the batteries are used for usagetime hours
    usagetime = 8
    yield env.timeout(usagetime)  # this yield timeout represents the usage time

    # after the usage return the ressources to the store.
    for k in resources_used:
        yield resources.put(k)

    print('-----------------------------------------')
    print('UseCase {}_{} that rented on day {}  used: {} Batteries for: {} hours'.format(n["usecase"], count, day,
                                                                                   resources_required, runtime))

    print('UseCase {}_{} that rented on day {} returned: {} Batteries at time: {}'.format(n["usecase"], count, day,
                                                                                    resources_required, env.now))
    print('-----------------------------------------')


# define an environment where the processes live in
env = simpy.Environment()

# define the store where the batteries are stored with "capacity" places
resources = simpy.Store(env, capacity=availability)

# fill the store with elements with an increasing id number
for i in range(resources.capacity):
    resources.put({'id': i})

# call the function that generates the individual rental processes
env.process(usecase_gen(env))

# start the simulation
env.run(until=runtime)

From https://groups.google.com/g/python-simpy/c/kb3JtarXwpM :https://groups.google.com/g/python-simpy/c/kb3JtarXwpM

The Problem is that Stores that come with SimPy 3 don't allow multiple items to be get or put at once.问题是 SimPy 3 附带的商店不允许一次获取或放置多个项目。 If you need to bottleneck on that kind of behavior, then you'll have to subclass a Store to do that for you如果您需要限制这种行为,那么您必须将 Store 子类化为您执行此操作

Subclassing is one option, in my case the solution was to change to a SimpyContainer, this resource type supports multiple Item get/put commands.子类化是一种选择,在我的情况下,解决方案是更改为 SimpyContainer,这种资源类型支持多个 Item get/put 命令。 This works partly for me as the items in the resource are all identical.这部分对我有用,因为资源中的项目都是相同的。

Now the problem remains that i need to label the individual resources for logging.现在问题仍然存在,我需要 label 用于记录的单个资源。

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

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