我正在寻找消息安排的最佳算法。我的意思是消息时间表是一种在我们有不同费率的消费者时在公交车上发送消息的方法。
示例: 假设我们有数据D1到Dn 。 D1每隔5ms发送给许多用户C1,C2每隔19ms,C3每隔30ms,Cn每隔Rn ms 。 Dn每隔10ms发送到C1,每31ms发送一次C2,每50ms发送一次Cn
使用最佳性能(CPU,内存,IO)安排此操作的最佳算法是什么?
此致
答案 0 :(得分:1)
我可以想到很多选择,每个选项都有自己的成本和收益。它真正归结为你的需求 - 真正定义的是什么,最好的"为了你。我已经伪装了以下几种可能性,希望能帮助你开始。
选项1:每个时间单位执行以下操作(在您的示例中为毫秒)
func callEachMs
time = getCurrentTime()
for each datum
for each customer
if time % datum.customer.rate == 0
sendMsg()
这样做的好处是不需要一致的存储内存 - 您只需在每个时间单位检查您是否应该发送消息。这也可以处理未在time == 0
发送的邮件 - 只是将邮件最初发送的时间存储为模式,并将条件替换为if time % datum.customer.rate == data.customer.firstMsgTimeMod
。
这种方法的缺点是它完全依赖于始终以1 ms的速率被调用。如果由于CPU上的另一个进程导致延迟并且它错过了一个周期,您可能会完全错过发送消息(而不是稍晚发送消息)。
选项2:维护元组列表的列表,其中每个条目代表在该毫秒内需要完成的任务。使列表至少与最长速率除以时间单位一样长(如果您的最长速率为50毫秒,并且您按ms进行,则列表必须至少为50长)。启动程序时,首次将消息发送到队列中。然后每次发送消息时,在下次将该消息发送到该列表时更新。
func buildList(&list)
for each datum
for each customer
if list.size < datum.customer.rate
list.resize(datum.customer.rate+1)
list[customer.rate].push_back(tuple(datum.name, customer.name))
func callEachMs(&list)
for each (datum.name, customer.name) in list[0]
sendMsg()
list[customer.rate].push_back((datum.name, customer.name))
list.pop_front()
list.push_back(empty list)
这样做的好处是避免了许多不必要的模数计算选项1。但是,这需要增加内存使用的成本。如果您的各种消息的速率存在很大差异,则此实现也不会有效(尽管您可以对此进行修改以更有效地处理更长速率的算法)。它仍然必须每毫秒调用一次。
最后,您必须非常仔细地考虑您使用的数据结构,因为这会对其效率产生巨大影响。因为您从前面弹出并在每次迭代时从后面推动,并且列表是固定大小,所以您可能希望实现circular buffer以避免不必要的值移动。对于元组列表,由于它们只是迭代(不需要随机访问),并且频繁添加,单链表可能是您的最佳解决方案。
显然,还有很多方法可以做到这一点,但希望这些想法能让你开始。另外,请记住,您运行此系统的系统的性质可能会对哪种方法更好地工作产生强烈影响,或者您是否想要完全执行其他操作。例如,两种方法都要求以一定的速率可靠地调用它们。我还没有描述并行实现,如果您的应用程序支持它们,这可能是最佳选择。
答案 1 :(得分:0)
与所描述的Helium_1s2类似,还有第二种方法,它基于我所谓的调度表,这就是我现在使用的,但这种解决方案有其局限性。
您可以看到我们必须提取我们的计划表,我们必须确定重复的传输周期和IDLE MINIMUM PERIOD的值。事实上,在1ms或1ns或1mn或1h的最小时间内循环是没用的(取决于具体情况)但是它并不总是最好的时期,我们可以如下优化这个循环。
例如一个(C1为6,C2为9),我们注意到有一个循环从0到18重复,两个连续发送事件的最小差异等于3。 所以:
HCF(6,9) = 3 = IDLE MINIMUM PERIOD
LCM(6,9) = 18 = transmission cycle length
LCM/HCF = 6 = size of our schedule table
计划表是:
,发送循环如下:
while(1) {
sleep(IDLE_MINIMUM_PERIOD); // free CPU for idle min period
i++; // initialized at 0
send(ScheduleTable[i]);
if (i == sizeof(ScheduleTable)) i=0;
}
这种方法的问题是如果LCM增长,这个数组会增长,如果我们有像rate / prime数字等那样的错误组合,那么