我需要一个算法(用于在php中使用)来管理我们的成员
我有一些成员,为我准备内容,
他们准备内容,完成后,等待让我去获取他们的内容(成员无法引用我),在我推荐他们并获取内容后,他们会为新内容工作,并且未定义下一个内容的时间将完成(每1个小时,我可以仅转到1个成员)
会员工作完全分开!
我的成员在工作速度上有所不同,有些成员很快,有些成员很慢
如果我使用FIFO方法去成员(考虑所有成员,同样速度),一些快速的成员,等待很长时间,对于其他一些慢的成员,我认为它们无效。
首先,我不知道会员的速度,并且应该考虑所有会员都有相同的速度,直到我检测到他们的速度
我按照以下方式登录会员:
╔════════╦════════════╦═══════════════════╗
║user id ║ last visit ║ work is complete? ║
╠════════╬════════════╬═══════════════════╣
║ 1 ║ 8:00 ║ Yes ║
║ 2 ║ 9:00 ║ No ║
║ 3 ║ 10:00 ║ No ║
║ 4 ║ 11:00 ║ Yes ║
║ 1 ║ 12:00 ║ Yes ║
║ 2 ║ 13:00 ║ No ║
║ 3 ║ 14:00 ║ No ║
║ 4 ║ 15:00 ║ Yes ║
║ 1 ║ 16:00 ║ Yes ║
║ 2 ║ 17:00 ║ Yes ║
║ 3 ║ 18:00 ║ Yes ║
║ 4 ║ 19:00 ║ Yes ║
╚════════╩════════════╩═══════════════════╝
在上面的例子中,用户1,4很快,用户2,3很慢
如何在快速用户访问次数较多时降低所有成员的优先级,并减慢用户访问次数,
如何检测哪个用户更适合下次访问?
感谢
答案 0 :(得分:3)
你可以用两个简单的队列来完成。 busy
队列和waiting
队列。 (请注意,在操作系统中,实际上有更多队列,其中最简单的是blocked
队列。)
busy
队列保存已有作业的任务(或工作成员,如果需要)。 waiting
队列保存已完成工作的任务。根据您的初始配置,其中一个队列已满,另一个为空(例如,如果最初没有人有作业,则busy
队列为空且waiting
已满)。
现在,您的任务分配算法非常简单:
Every 1 hour
If waiting.empty // If no one previously-known to be without a job
Linearly search busy and find who has finished their job
Add them in order to waiting while removing them from busy
(So, search busy from head to tail and add to waiting from tail)
If !waiting.empty // If now there is someone without a job
Assign a job to waiting.head and put it in the end of busy
该算法通过保持任务顺序确保没有饥饿。因此,例如,如果两个任务非常快并且其他任务永远存在,则算法在两个快速任务之间保持交替(而不是仅一直给它们中的一个任务)。
现在你可能真的想要提供最快的工作,即使他得到所有的工作而其他工作都没有(不太可能,但我不知道你的目标)。在这种情况下,您需要一些簿记来对任务进行排名。例如,任务分配给他们的时间以及他们完成任务的时间。这意味着上述算法中的线性搜索应该每小时完成一次(而不是仅在waiting
为空时)。
因此,waiting
成为最大优先级队列,其中优先级越高,任务越快。因此,如果它没有忙,那么最快的任务总会首先出现。
如果您想使用此算法在某种程度上补偿饥饿,您可以为每个任务添加age
,每次waiting
时都会增加,而不会找到工作。然后,优先级将是任务的速度和年龄的组合。如果你有两者的线性组合,你就不需要在任务老化时重新排列优先级队列,因为排序保持不变(因为它们同时会以相同的数量老化)。
编辑尽管我不明白为什么在php中你每个计划时间只能找一个成员,但无论如何我都有你的解决方案。
由于您没有关于成员速度的任何信息,因此首先分配每个任务是不可避免的。这是学习阶段。因此无论任何结构保存任务,起初它应该像FIFO一样。
逐渐了解成员的速度,您需要更好地将它们排列在队列中。
嗯,这与上面的部分(使用优先级队列)的算法非常相似,你可以实现这一点。
首先,对于每个成员,保留三个值:work_time_start
,min_work_time
和max_work_time
。它们代表您理解成员完成任务所需的时间。在为成员分配工作时,您可以设置其work_start_time
。每次在算法中的任何位置访问该节点时,都会根据其是否完成任务,更新其min_work_time
或max_work_time
。最初min_work_time
为1,max_work_time
为无穷大。
现在你可以拥有三个(优先级)队列; waiting
,busy
,maybe_busy
。前两个队列和以前一样。第三个是你不确定他们是否完成任务的任务。换句话说,它包含当前执行时间介于min_work_time
和max_work_time
之间的任务。
注意:我假设您只能去一次任务,但您可以根据需要检查您的簿记(可能包含不精确的数据)。那可以吗?
所以这是新算法:
Every one hour
// Note: busy is a min-priority queue on work_start_time + min_work_time
while busy.head satisfies (time() - work_start_time >= min_work_time)
remove busy.head and add it to maybe_busy
// Note: maybe_busy is a min-prioiry queue on work_start_time + max_work_time
while maybe_busy.head satisfies (time() - work_start_time >= max_work_time)
remove maybe_busy.head and add it to waiting
// Note: waiting is a min-priority queue on min_work_time
If !waiting.empty
take waiting.head
assign a task to it
put it in busy
Else
go to maybe_busy.head
If it is still busy
update its min_work_time
remove from maybe_busy and add to busy
sorry, but you can't assign a task this hour
If it is not busy
remove from maybe_busy
update its max_work_time
assign a task to it
put it in busy
算法可能看起来很复杂,我可能已经介绍了一些错误,但这个概念非常简单。任务有三种状态:
WAITING
/ \
BUSY -- MAYBE BUSY
WAITING
任务肯定是免费的,因此您始终可以为其分配任务。 BUSY
任务肯定很忙,所以你不需要去找他们。
busy
是work_start_time + min_work_time
上的最小优先级队列,这意味着查看其头部,您将获得可能已完成其工作的第一个成员。如果是这样,它将被移动到maybe_busy
(并重复直到头部仍然确定忙)
maybe_busy
是work_start_time + max_work_time
上的最小起始队列,这意味着看到它的头部,你得到第一个肯定已经完成工作的成员。如果是这样,它会被移动到waiting
(并重复直到头部仍然未知是否繁忙)
两个第一个while
循环是簿记的,并且不要求您真正去找会员。它们是根据您目前收集的信息进行管理的。
然后,检查waiting
。如果它不是空的,那么你有一个肯定可用的成员。你只需要去做它并给它一个任务。只是把他放在busy
,因为你刚给了他一份工作。
如果waiting
为空,那么你不得不去找一个你怀疑大部分会完成工作的成员(maybe_busy
的负责人)并询问他是否已经完成。
如果他没有完成,你会更新它的min_work_time
,所以将来你知道他比你想象的要慢。然后你需要将他添加到busy
因为他现在很忙(你刚刚问他!)
如果他完成了,你会更新它的max_work_time
,所以将来你知道他比你以前更快。然后,您可以为其分配一个任务并将其添加到busy
,因为您只是给了他一份工作。
首先,这个算法会继续将每个算法放在maybe_busy
中并逐个进入它们,所以最初它就像一个FIFO。然而,在第一次迭代之后,它将基本了解每个任务可能需要多长时间,并且可以更好地猜测它应该首先执行哪个任务。每次访问后,统计数据都会得到完善。
注意:此算法仍然存在饥饿问题。如果算法计算出超快速成员,它将不断给他工作。如果您不希望饥饿用于其他任务,您将再次需要介绍age
。