简单资源可用性计划

2024-05-18 05:37:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我在Python中使用SimPy来创建一个离散事件模拟,它需要根据用户在csv文件中输入的时间表提供资源。其目的是代表在一天中不同时间提供的相同资源(如员工)的不同数量。据我所知,这不是基本SimPy类资源优先级中可用的。在

我已经设法使这个工作,并已包括下面的代码来说明如何。然而,我想问社区是否有更好的方法在SimPy中实现这个功能?在

下面的代码的工作原理是在每天开始时请求不可用的资源,并以更高的优先级确保资源得到。然后在适当的时间释放资源供其他事件/进程使用。正如我所说的,它是有效的,但是由于有许多虚拟进程在工作,以确保资源的正确真实可用性,这似乎是浪费。欢迎提出任何有助于改进的意见。在

所以csv看起来像:

Number  time
0        23
50       22
100      17
50       10
20       8
5        6

其中Number表示在定义的时间可用的员工数量。例如:6-8有5个员工,8-10有20个员工,10-17个有50个员工,以此类推,直到一天结束。在

代码:

^{pr2}$

Tags: 文件csv代码用户目的number数量进程
3条回答

我尝试了其他方法,重载了Resource类,只添加了一个方法,虽然我不能完全理解源代码,但它似乎可以正常工作。您可以告诉资源更改模拟中某处的容量。在

from simpy.resources.resource import Resource, Request, Release
from simpy.core import BoundClass
from simpy.resources.base import BaseResource

class VariableResource(BaseResource):
    def __init__(self, env, capacity):
        super(VariableResource, self).__init__(env, capacity)
        self.users = []
        self.queue = self.put_queue

    @property
    def count(self):
        return len(self.users)

    request = BoundClass(Request)
    release = BoundClass(Release)

    def _do_put(self, event):
        if len(self.users) < self.capacity:
            self.users.append(event)
            event.usage_since = self._env.now
            event.succeed()

    def _do_get(self, event):
        try:
            self.users.remove(event.request)
        except ValueError:
            pass
        event.succeed()

    def _change_capacity(self, capacity):
        self._capacity = capacity

我认为这应该行得通,但我对触发器的工作原理并不是百分之百的自信。在

这就是我在申请中解决这个问题的方法。它并不完美,但考虑到我对Python和SimPy的基本技能,它是我所能做的最好的。在

结果是,在期望的时间,顾问的数量是正确的。在

首先,我定义一个存储并将容量设置为等于模拟中将存在的advisor实例的总数。在

self.adviser_store = simpy.FilterStore(self.env,
capacity=self.total_ad_instances)

所需的advisor类的实例是在初始化步骤中创建的,为了简洁起见,我没有包括这一步。实际上,我使用一个JSON文件来定制各个advisor实例,然后将它们放入一个列表中。在

下面的类定义中的run参数实际上是另一个类,它包含与当前模拟运行相关的所有信息,因此例如它包含模拟的开始和结束日期。自我开始日期因此确定顾问开始工作的日期。self.run.start_日期是模拟的开始日期。在

^{pr2}$

如您所见,创建advisor类也会启动设置可用性的过程。在下面的示例中,我将其简化为在给定的日期范围内每天都设置相同的可用性。当然,您可以根据日期/日期等设置不同的可用性

def set_availability(self):

    start_delay = self.start_time + (self.start_date - self.run.start_date).total_seconds()/3600 # this returns the time in hours until the resource becomes available and is applied below.
    end_delay = self.end_time + (self.start_date - self.run.start_date).total_seconds()/3600
    repeat = (self.end_date - self.start_date).days + 1  # defines how man days to repeat it for

    for i in range(repeat):

        start_delayed(self.run.env, self.add_to_store(), start_delay)
        start_delayed(self.run.env, self.remove_from_store(), end_delay)
        start_delay += 24
        end_delay += 24

    yield self.run.env.timeout(0)


def add_to_store(self):

    self.run.ad_avail.remove(self)  # take adviser from a list
    self.run.adviser_store.put(self)  # and put it in the store
    yield self.run.env.timeout(0)

def remove_from_store(self):        

    current_ad = yield self.run.adviser_store.get(lambda item: item.id_num == self.id_num)  # get itself from the store 
    self.run.ad_avail.append(current_ad) # and put it back in the list
    yield self.run.env.timeout(0)

因此,从本质上讲,顾客只能向商店要求顾问,而顾问只会在特定时间出现在店里。其余时间它们将显示在附加到当前仿真运行的列表中。在

我认为这里还有一个陷阱。当顾问对象即将不可用时,它可能正在使用中。我还没有注意到这种情况是否会发生,也没有注意到如果发生的话会产生什么影响。在

简单相关

也许你可以使用PreemptiveResource(参见this example)。这样,每个资源只需要一个拦截器进程,因为它可以“踢”不太重要的进程。在

与Python相关的

  • 记录你的代码。take_res()和{}的目的是什么?(为什么这两个函数都使用priority=-100?)在
  • 用更好的名字。the_list或{}没有多大帮助。在
  • 代替the_list.append(row[0], row[1])你可以做the_list.append(row[:2])。在
  • 为什么要将列表列表转换成元组?就我所能看到的好处而言。但它增加了额外的代码,从而增加了额外的混乱和编程错误的可能性。在
  • 您应该尽快离开with open(file)块(在您的例子中,在前四行之后)。不需要将文件打开超过必要的时间,当您遍历完所有行之后,就不再需要它了。在

相关问题 更多 >