优先队列同时防止饥饿
prioritized queue while preventing stravation
这是我的问题:
我有数千个传感器要轮询。每个传感器都有一个轮询间隔(不固定,而是随时间变化)。
所以我需要一个接一个地高效地轮询它们。
为此,我可以使用优先级队列(以轮询时间戳为键)。
问题是可以忽略传感器:
例如,如果有一个传感器需要每 15 分钟轮询一次,并且有大量传感器需要每 5 分钟轮询一次,那么优先级队列可能会优先于第一个传感器。
所以我可以使用几个优先级队列而不是一个,但是如何选择下一个传感器进行轮询的问题仍然存在。
我的问题的理想解决方案是什么?
谢谢。
以下可能是解决您的问题的方法:
1) 如果需要处理大量不同的优先级,那么建议使用单个优先级队列。基本上,您需要在等待一段时间后将低优先级作业的优先级提高到高优先级作业。这样你就可以处理低优先级作业无限期饥饿的情况,但如果有很多低优先级作业,你可以暂时饥饿高优先级作业。
2) 当可用的优先级作业种类有限时,建议使用多个队列。现在这些队列中的每一个都拥有特定的优先级作业。因此,对于从低优先级队列中取出的每个作业,您可以从较高优先级队列中轮询多个作业。这有助于降低低优先级作业的饥饿率。
如果您使用计划的轮询时间作为优先级,您可能无法跟上轮询,但您不会遇到某些传感器永远不会轮询的饥饿问题。
Java的DelayQueue
is a good fit for this. Store the scheduled time in the Delayed
实例(基于System.nanoTime()
),然后实现getDelay()
来计算与当前System.nanoTime()
之间的差异.
因为DelayedQueue
是一个并发队列,多个消费者可以接受任务和运行他们,并独立地重新安排新的任务。这将有助于跟上负载并保持您的日程安排,因为在轮询慢速传感器时,另一个线程可能正在等待下一个任务有资格执行。
假设您有两个传感器:每秒轮询一次的传感器 A 和每 3 秒轮询一次的传感器 B,以及按预定轮询时间排序的队列。
time 0: A polled, rescheduled for time 1
B polled, rescheduled for time 3
time 1: A polled, rescheduled for time 2
time 2: A polled, rescheduled for time 3
time 3: A polled, rescheduled for time 4
B polled, rescheduled for time 6
时间 3 的轮询顺序不确定,但 B 肯定会在时间 4 安排的任何传感器之前轮到轮询。
来自 OP 评论:
sensors don't get out of the queue, but rather their keys get updated
那你就错了。优先级队列没有键,但如果有,它们将不支持键突变。
队列是一个集合,生产者向其添加元素,消费者从中移除元素。如果其内容没有改变,请使用不同的集合。
如果有时工作太多而无法按时完成所有事情,您有两个基本选择:做所有事情,并接受有些人会迟到或跳过一些工作,以完成最重要的任务及时。哪种方法合适取决于您的应用程序,但从您可能永远赶不上的意义上说,第一种方法很脆弱。
什么都晚做
如果你必须做所有的工作,但不在乎什么时候做,你可以使用两个优先级。第一个是时间表,如前所述。第二个是 "importance" 指标,用于确定已准备好执行的任务的优先级。
少量工作线程(可能只有一个)消耗 DelayedQueue
,根据其计划等待任务。然而,这些工作人员并没有直接执行任务,而是根据任务的重要性简单地将任务放入另一个 BlockingQueue
中。更多的工作人员使用这个队列,首先执行最重要的任务。
如果平均负载大于可用容量,此队列将继续增长。否则,所有的工作最终都会完成,一旦任务准备好执行,您就可以设计任何您喜欢的策略来确定任务的优先级。
按时做事
可能迟到的样本没有价值,宁可跳过polling,也不要越拖越远。在这种情况下,可以为每个任务指定一个 "grace period"。当它从DelayQueue
出来时,检查当前时间是否在执行的宽限期内。如果是这样,请继续执行任务。否则,放弃任务并获得下一个。宽限期可能是轮询频率的函数,周期越长,宽限期越长,而跳过高频任务有助于快速清空队列,而不会长时间丢失样本。
混合
您可以将 "grace period" 的想法与第一种方法结合起来,让最重要的任务有最好的机会按时执行,但是当任务来不及为了赶上有用时就跳过任务向上。
单线程
所有这些策略对于单个线程执行任务仍然有用,但是当一个线程连续执行相对较长的任务时,保持进度是一项相当艰巨的任务 - 运行ning 任务,如轮询物理传感器。
即使处理器是单核的,一次只执行一个线程,它仍然支持通过上下文切换进行线程调度,以便在其他任务被阻塞时可以在另一个任务上取得进展I/O.这将更好地保留所需的时间表。
这是我的问题:
我有数千个传感器要轮询。每个传感器都有一个轮询间隔(不固定,而是随时间变化)。
所以我需要一个接一个地高效地轮询它们。
为此,我可以使用优先级队列(以轮询时间戳为键)。
问题是可以忽略传感器:
例如,如果有一个传感器需要每 15 分钟轮询一次,并且有大量传感器需要每 5 分钟轮询一次,那么优先级队列可能会优先于第一个传感器。
所以我可以使用几个优先级队列而不是一个,但是如何选择下一个传感器进行轮询的问题仍然存在。
我的问题的理想解决方案是什么?
谢谢。
以下可能是解决您的问题的方法:
1) 如果需要处理大量不同的优先级,那么建议使用单个优先级队列。基本上,您需要在等待一段时间后将低优先级作业的优先级提高到高优先级作业。这样你就可以处理低优先级作业无限期饥饿的情况,但如果有很多低优先级作业,你可以暂时饥饿高优先级作业。
2) 当可用的优先级作业种类有限时,建议使用多个队列。现在这些队列中的每一个都拥有特定的优先级作业。因此,对于从低优先级队列中取出的每个作业,您可以从较高优先级队列中轮询多个作业。这有助于降低低优先级作业的饥饿率。
如果您使用计划的轮询时间作为优先级,您可能无法跟上轮询,但您不会遇到某些传感器永远不会轮询的饥饿问题。
Java的DelayQueue
is a good fit for this. Store the scheduled time in the Delayed
实例(基于System.nanoTime()
),然后实现getDelay()
来计算与当前System.nanoTime()
之间的差异.
因为DelayedQueue
是一个并发队列,多个消费者可以接受任务和运行他们,并独立地重新安排新的任务。这将有助于跟上负载并保持您的日程安排,因为在轮询慢速传感器时,另一个线程可能正在等待下一个任务有资格执行。
假设您有两个传感器:每秒轮询一次的传感器 A 和每 3 秒轮询一次的传感器 B,以及按预定轮询时间排序的队列。
time 0: A polled, rescheduled for time 1 B polled, rescheduled for time 3 time 1: A polled, rescheduled for time 2 time 2: A polled, rescheduled for time 3 time 3: A polled, rescheduled for time 4 B polled, rescheduled for time 6
时间 3 的轮询顺序不确定,但 B 肯定会在时间 4 安排的任何传感器之前轮到轮询。
来自 OP 评论:
sensors don't get out of the queue, but rather their keys get updated
那你就错了。优先级队列没有键,但如果有,它们将不支持键突变。
队列是一个集合,生产者向其添加元素,消费者从中移除元素。如果其内容没有改变,请使用不同的集合。
如果有时工作太多而无法按时完成所有事情,您有两个基本选择:做所有事情,并接受有些人会迟到或跳过一些工作,以完成最重要的任务及时。哪种方法合适取决于您的应用程序,但从您可能永远赶不上的意义上说,第一种方法很脆弱。
什么都晚做
如果你必须做所有的工作,但不在乎什么时候做,你可以使用两个优先级。第一个是时间表,如前所述。第二个是 "importance" 指标,用于确定已准备好执行的任务的优先级。
少量工作线程(可能只有一个)消耗 DelayedQueue
,根据其计划等待任务。然而,这些工作人员并没有直接执行任务,而是根据任务的重要性简单地将任务放入另一个 BlockingQueue
中。更多的工作人员使用这个队列,首先执行最重要的任务。
如果平均负载大于可用容量,此队列将继续增长。否则,所有的工作最终都会完成,一旦任务准备好执行,您就可以设计任何您喜欢的策略来确定任务的优先级。
按时做事
可能迟到的样本没有价值,宁可跳过polling,也不要越拖越远。在这种情况下,可以为每个任务指定一个 "grace period"。当它从DelayQueue
出来时,检查当前时间是否在执行的宽限期内。如果是这样,请继续执行任务。否则,放弃任务并获得下一个。宽限期可能是轮询频率的函数,周期越长,宽限期越长,而跳过高频任务有助于快速清空队列,而不会长时间丢失样本。
混合
您可以将 "grace period" 的想法与第一种方法结合起来,让最重要的任务有最好的机会按时执行,但是当任务来不及为了赶上有用时就跳过任务向上。
单线程
所有这些策略对于单个线程执行任务仍然有用,但是当一个线程连续执行相对较长的任务时,保持进度是一项相当艰巨的任务 - 运行ning 任务,如轮询物理传感器。
即使处理器是单核的,一次只执行一个线程,它仍然支持通过上下文切换进行线程调度,以便在其他任务被阻塞时可以在另一个任务上取得进展I/O.这将更好地保留所需的时间表。