Anylogic - 创建资源并添加到 ResourcePool
Posted
技术标签:
【中文标题】Anylogic - 创建资源并添加到 ResourcePool【英文标题】:Anylogic - create Resources and add to ResourcePool 【发布时间】:2021-11-13 21:28:48 【问题描述】:我很难找到使用 Resources 和 resourcePools 所需的文档 - 我找不到“资源 API 文档”。
我想以编程方式创建静态资源(自定义类型),然后将这些资源添加到资源池。创建资源时,我希望能够在将它们添加到资源池之前指定它们的属性值。在我看来,代码看起来像这样:
Room myRoom;
myRoom = new Room("redRoom", 20);
addTo_myResourcePool(myRoom);
myRoom = new Room("greenRoom", 10);
addTo_myResourcePool(myRoom);
有谁知道是否有办法达到这个目的?
【问题讨论】:
【参考方案1】:这在 AnyLogic 中有点盲点。只能间接完成:
-
使用您的代理类型创建一个空代理群体
告诉资源池使用该代理类型
根据需要设置资源池容量。该池将为您在该人群中创建代理(如果容量大于当前资源数量)
如果要手动创建资源,必须调用myResourcePool.set_Capacity(myResourcePool.getCapacity()+1)
销毁 1 个资源反之亦然。
另外,请确保“在容量减少时破坏资源”,以便从人口中消灭特工
【讨论】:
@CrustyNoodle 您还可以参数化通过在资源池参数的New resource Unit:
部分中以编程方式创建新代理来创建的代理。这是您可以使用new myAgent()
以编程方式创建代理并在流程图中使用它们的少数几个地方之一。
@Jaco-BenVosloo 资源池的“On new unit”操作允许您配置刚刚创建的资源单元(不是创建一个)。这就是 OP 需要为他的新资源单元自定义参数值。
还请注意,您通常不是通过set_Capacity
明确(以编程方式)创建新代理。 (比如说,您是通过计划隐式创建它们。)然后您仍然可以通过“在新单元上”操作对新创建的资源单元进行参数化。
但是资源池的工作方式存在各种问题/限制(正如 Ben 所暗示的),这些问题/限制限制了您在“控制”一组具有不同属性的资源单元方面的能力;在 某些 情况下,最好/有必要根本不使用资源池并有效地编写自己的占用/释放逻辑(包括轮班结束等),尽管这有其自身的一系列问题当然(例如不“链接”到诸如优先级和抢占之类的东西)。
“在某些情况下,最好/有必要根本不使用资源池” -> 不幸的是,这是真的。【参考方案2】:
我为此使用了一个技巧,有时会奏效,但我不会将其概括为最终解决方案......我只在我有几个不同的单位特征时才这样做,这似乎是你的情况。
第一步:创建resourcePools的种群...每个资源池都会对应一种agent特征,所有resourcePools使用相同的resource(agent)类型
第2步:在资源池的新单元中,您将使用resourcePool人口的索引来生成具有特定特征的单元......然后您可以执行类似resourcePool.get(i).set_capacity (无论如何)为了生成具有您想要的确切特征的资源单元
第 3 步:当您获取资源时,您将使用替代方案...资源池人口中的每个资源池将是可供使用的替代方案中的 1 个选项...您将需要创建一个函数来返回 ResourcePool[] []
第 4 步:您将使用条件根据其特性选择单元(自定义资源选择)
【讨论】:
感谢 Felipe,这是创建大量资源组的非常简洁的方法。在这种情况下,它接近我的要求,但我会接受 Ben 的回答,因为它更接近解决方案的根源,并且应该在此过程中帮助其他人。【参考方案3】:一种选择是创建一个资源代理群体,我假设它是基于您的代码的房间类型。
然后你就有了一个函数,它将向人口中添加一个新代理并将其返回给调用者。
现在你只需要将这个添加到资源池对象中的new resource unit
调用中
不要更改“添加单位”选项,因为我们已经在函数中这样做了。
我在一个小型模型中对此进行了测试,方法是使用两个按钮来增加和减少执行期间的容量
resourcePool.set_capacity(max(0, resourcePool.size() + 1));
和
remove_myResource(myResource.get(myResource.size()-1));
resourcePool.set_capacity(max(0, myResource.size()));
【讨论】:
感谢 Jaco,这听起来是一个非常适合我用例的解决方案。我现在将尝试实施它。 再次感谢 Jaco,此方法有效,但在尝试将单个单元参数传递给 getNewRoom() 方法时有点混乱。我实施的解决方案首先设置 ResourcePool 容量并将新单位放入自定义人口中。然后我遍历自定义总体以设置每个单元的参数。我只需要在跑步开始时执行一次。不是一个特别优雅的解决方案,但它有效。我将继续查看是否可以干净地实施您的解决方案。 我会非常厌倦从人口中删除资源然后减小资源池的大小 - 不能保证您从人口中删除的代理和资源池删除的资源单元是相同的事情。【参考方案4】:这里有几个相关的点。
AnyLogic 的设计目的是让您仅通过更改池的容量来更改资源池中的代理。这可以通过池的set_capacity
函数直接完成(如果池的容量设置为“直接”定义),但更常见的是通过链接池的容量到一个时间表(表示班次模式或任何其他预定义的容量随时间的变化)。
资源池在容量减少时默认保留代理(即它们存在但“不可用”),但您可以将其设置为删除它们。您需要什么取决于资源和任何特定于资源的属性/状态所代表的内容。
如果您需要单独寻址/访问资源池中的代理,而不是将它们用作被扣押/释放的资源,您可以让资源池将它们存储在自定义群体中(而不是将它们与所有其他代理一起放入默认群体中)不是在自定义人口中创建的)通过“将单位添加到”设置。然后,您可以在需要时显式访问该群体(例如,循环访问它)。否则这方面是没有必要的。
如果您的资源池是具有参数的自定义代理(或需要以特定方式初始化的其他状态),标准方法是直接/间接增加容量创建单元(使用默认参数值),然后执行任何操作在“On new unit”操作中进行后续初始化(您可以通过 agent
关键字访问新创建的单元)。
您可以或者通过“新资源单元”的动态表达式来完成它(如 Jaco 的回答),但这并没有特别为您带来任何好处(尽管它同样有效)。是的,它有点“面向对象”,但是无论如何,AnyLogic 都为以适当的 OO 方式做事设置了很多障碍——正如你所说,更“明显”的 OO 方法只是在添加/删除代理的资源池。基本上,创建代理的块(如资源池或源块)的标准“设计模式”是让它使用默认信息创建它们,然后在适当的操作中对其进行自定义。
您也可以使用资源池代理的“启动时”操作 / 代替,但通常您将使用来自包含进程的代理的信息来确定新资源代理应该具有什么状态,这使得“启动时”操作不太有用。
最后(!),如果您有一组不变的资源池代理,并且一起初始化它们更容易(例如,因为所有它们都有一些数据库输入数据,因此可以循环一次),那么只需在包含资源池的代理的“启动时”操作中执行此操作(在资源池初始化并创建默认状态代理之后运行)。 将需要它们在一个自定义群体中,这样您就可以只循环通过这些代理。但您的问题似乎暗示您担心动态添加资源代理。
但是,正如我的其他一些 cmets 所指出的,资源池的工作方式存在各种微妙之处/限制(实际上是基于它们目前被设计为一个池,其中每个人的明确身份不是完全“可控”的),这意味着您实际需要的可能超出此范围。
几个例子:
如果您希望您的资源是明确的个人员工,并且可以跨班次跟踪信息(例如,随着他们的状态发生变化以反映他们所执行任务的经验或历史记录),您就会遇到无法控制的复杂情况哪些资源(如果您没有在容量减少时删除它们)在容量更改时“回来”,因此您可能需要更复杂的解决方法,例如为每个不同的班次设置单独的资源池并从资源中获取包含所有此类池的集合 — 在任何给定时间,只有其中一个(活动班次一)将具有非零容量,除非班次重叠。
如果容量减少(表示轮班结束),您无法控制/确定哪些资源代理被选择下班。另外,资源代理在实际“离开”之前仍处于活动状态,完成任务存在问题(鉴于班次结束未设置为先发制人)——因为如果您再次增加容量,它们在完成之前仍然存在在他们工作时,AnyLogic 不会创建新的资源代理(它只会将此现有代理添加回池中作为“活动”代理)。所以这使得其他一些事情变得更加困难......
【讨论】:
感谢斯图尔特,这是对事物的非常完整的解释。它肯定突出了资源实现中的一些缺点,特别是控制单个资源的能力。不幸的是,资源池中的所有资源并非总是相同的,因此控制哪些资源在轮班结束时“退役”或实际上在发布块中释放哪些资源对于某些用例可能至关重要。在这种情况下,我采用了您的“Finally(!)”解决方案,因为我能够在模拟开始时一次性创建所有资源。以上是关于Anylogic - 创建资源并添加到 ResourcePool的主要内容,如果未能解决你的问题,请参考以下文章