Simmer 资源在容量不为 0 时不会减少到达。

huangapple go评论54阅读模式
英文:

R simmer resource not dropping arrival when capacity --> 0

问题

在我的模拟中,某些资源按照容量计划安排,根据一天中的时间交替变化为0和1。如果一个资源在其容量降为零之前无法完成任务,那么到达请求应该被丢弃,等待一段时间,然后回滚以尝试选择一个可用的资源。如果没有可用的资源,到达请求会经历一个超时-->回滚循环,直到有一个可用的资源。

相关代码如下:

# 使用一个拒绝轨迹来返回并选择一个新的资源,如果当前资源用尽了时间(即其班次结束)
... |> 
simmer::seize_selected(
  continue = TRUE,
  reject = simmer::trajectory('dropped') |>
    simmer::timeout(\() runif(1, min = 0.07, max = 0.1)) |>
    simmer::rollback(target = 'select_resource')
  ) |>

# 当选定资源的容量为零时,清空队列
simmer::renege_if(
  signal = 'clear_queue'
  ) |>
simmer::send(
  signals =  \() {
    cap <- simmer::get_capacity_selected(env)

    res_name <- simmer::get_selected(env)
    now <- simmer::now(env)

    queue_count <- simmer::get_queue_count_selected(env)
    if (res_name == 'Operator_Bill' & now > 41 & queue_count > 0) {
      browser()
    }

    if (cap == 0) {
      'clear_queue'
      } else {
        ''
      }
    }
  ) |> ...

出于某种原因,调试条件从未触发,但检查mon_resources显示到达请求在容量为0时正在提供/排队。处理这种情况的正确代码是什么?

英文:

In my simulation, certain resources are on a capacity schedule, which alternates between 0 and 1 based on the time of day. If a resource cannot complete its task by the time its capacity goes to zero, the arrival should be dropped, wait a short period, and rollback to try to select an available resource. If no resource is available, the arrival goes through a timeout --> rollback loop until a resource becomes available.

The relevant code is as follows:

# Use a reject trajectory used to go back and select a new resource if the
# current resource runs out of time (i.e., its shift ends)
... |> 
simmer::seize_selected(
  continue = TRUE,
  reject = simmer::trajectory('dropped') |>
    simmer::timeout(\() runif(1, min = 0.07, max = 0.1)) |>
    simmer::rollback(target = 'select_resource')
  ) |>

# Clear the queue of the selected resource when its capacity is zero
simmer::renege_if(
  signal = 'clear_queue'
  ) |>
simmer::send(
  signals =  \() {
    cap <- simmer::get_capacity_selected(env)

    res_name <- simmer::get_selected(env)
    now <- simmer::now(env)

    queue_count <- simmer::get_queue_count_selected(env)
    if (res_name == 'Operator_Bill' & now > 41 & queue_count > 0) {
      browser()
    }

    if (cap == 0) {
      'clear_queue'
      } else {
        ''
      }
    }
  ) |> ...

The debug condition is never triggered for some reason, but on inspecting mon_resources it shows that arrivals are being served/in queue when capacity == 0. What would be the correct code to handle this situation?

Simmer 资源在容量不为 0 时不会减少到达。

Simmer 资源在容量不为 0 时不会减少到达。

答案1

得分: 1

这是你问题的简化示例:

library(simmer)

t <- trajectory() %>%
  seize("res") %>%
  timeout(Inf)

simmer() %>%
  add_resource("res", capacity=schedule(c(0, 5), c(1, 0))) %>%
  add_generator("dummy", t, at(0)) %>%
  run(10)
#> simmer环境: 匿名 | 当前时间: 10 | 下一步: Inf
#> { 监视器: 内存中 }
#> { 资源: res | 监视中: TRUE | 服务器状态: 1(0) | 队列状态: 0(Inf) }
#> { 源: dummy | 监视中: 1 | 已生成数量: 1 }

在上面的示例中,一个到达事件占用了资源并等待。在t=5时资源"关闭",这要归功于指定的调度。但在t=10时的模拟状态中,我们可以看到到达事件仍然在服务器中。这就是你想要实现的:

t <- trajectory() %>%
  handle_unfinished(trajectory() %>% log_("dropped!")) %>%
  seize("res") %>%
  timeout(Inf)

simmer() %>%
  add_resource("res", capacity=schedule(c(0, 5), c(1, 0)),
               queue_size=0, queue_size_strict=TRUE, preemptive=TRUE) %>%
  add_generator("dummy", t, at(0)) %>%
  run(10)
#> 5: dummy0: dropped!
#> simmer环境: 匿名 | 当前时间: 5 | 下一步: 
#> { 监视器: 内存中 }
#> { 资源: res | 监视中: TRUE | 服务器状态: 0(0) | 队列状态: 0(0) }
#> { 源: dummy | 监视中: 1 | 已生成数量: 1 }

现在到达事件被丢弃了。有几点需要注意:

  • 默认情况下,资源不具有抢占性,这意味着即使容量降低,成功占用资源的到达事件仍将保留在那里。因此,我们首先需要指定preemptive=TRUE标志。
  • 使用此标志,到达事件会从服务器中被丢弃,但它将保留在队列中。因此,我们需要指定queue_size=0,但也要指定queue_size_strict=TRUE,因为抢占的到达事件默认允许超过队列大小。现在,到达事件从资源中被有效丢弃。
  • 最后,如果你想处理被丢弃的到达事件,seizereject参数不起作用,因为到达事件不是被拒绝的:它是在访问资源后被丢弃的。这个谜题的最后一部分是handle_unfinished()活动,它被设计用来处理这些特殊情况。
英文:

Here's a simplified example of your question:

library(simmer)

t &lt;- trajectory() %&gt;%
  seize(&quot;res&quot;) %&gt;%
  timeout(Inf)

simmer() %&gt;%
  add_resource(&quot;res&quot;, capacity=schedule(c(0, 5), c(1, 0))) %&gt;%
  add_generator(&quot;dummy&quot;, t, at(0)) %&gt;%
  run(10)
#&gt; simmer environment: anonymous | now: 10 | next: Inf
#&gt; { Monitor: in memory }
#&gt; { Resource: res | monitored: TRUE | server status: 1(0) | queue status: 0(Inf) }
#&gt; { Source: dummy | monitored: 1 | n_generated: 1 }

In the example above, an arrival seizes a resource and stays there. The resource "closes" at t=5 thanks to the specified schedule. But then in the simulation status at t=10 we can see that the arrival is still in the server. And this is what you are trying to achieve:

t &lt;- trajectory() %&gt;%
  handle_unfinished(trajectory() %&gt;% log_(&quot;dropped!&quot;)) %&gt;%
  seize(&quot;res&quot;) %&gt;%
  timeout(Inf)

simmer() %&gt;%
  add_resource(&quot;res&quot;, capacity=schedule(c(0, 5), c(1, 0)),
               queue_size=0, queue_size_strict=TRUE, preemptive=TRUE) %&gt;%
  add_generator(&quot;dummy&quot;, t, at(0)) %&gt;%
  run(10)
#&gt; 5: dummy0: dropped!
#&gt; simmer environment: anonymous | now: 5 | next: 
#&gt; { Monitor: in memory }
#&gt; { Resource: res | monitored: TRUE | server status: 0(0) | queue status: 0(0) }
#&gt; { Source: dummy | monitored: 1 | n_generated: 1 }

And now the arrival is dropped. Several things to note:

  • By default, resources are not preemptive, which means that, even if the capacity drops, the arrivals that managed to seize the resource will still be there. So the first thing we need is to specify the preemptive=TRUE flag.
  • With this flag, the arrival is dropped from the server, but it will stay in the queue. Therefore, we need to specify queue_size=0, but also queue_size_strict=TRUE, because preempted arrivals are by default allowed to exceed the queue size. And now the arrival is effectively dropped from the resource.
  • Finally, if you want to handle the dropped arrival, seize's reject argument won't work, because the arrival was not rejected: it was dropped after accessing the resource. The last piece of the puzzle is the handle_unfinished() activity, which was designed to handle these special cases.

huangapple
  • 本文由 发表于 2023年4月20日 00:10:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76056706.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定