程序员经典面试题,设计定时任务调度器,使用什么算法和数据结构,如何实现一个定时任务?为了简化问题,我们只需要考虑内存解决方案,而不考虑数据持久化。数组方法是最简单的。我们可以将所有的任务存储在一个数组中,然后每单位时间遍历整个数组,找出是否有满足当前时间的任务。如果是,则将其从数组中取出并执行。单位时间内的查询算法复杂度为O(N)。那么,如何添加新任务呢?我们只需要简单地向数组添加一个元素。算法时间复杂度是O(1)优先级队列方法评价一个算法,我们要考虑它的查询算法的复杂度,还要考虑他的插入算法的复杂度。在定时任务场景中,显然,查询的场景非常多。几乎每个单位时间我们都要轮询一次,那么我们有没有可能优化算法呢?每次查询,我们只需要查询离当前时间最近的时间,早于当前时间的,就要丢弃。所以这个题目就相当于我们用时间最少的查询队列。我们不禁想到一个熟悉的数据结构,优先队列!或者我们可以使用一个小的根堆来实现。每次我们插入一个新的计划任务时,我们都会将一个任务插入到优先级队列中。每次插入都需要调整队列,算法时间复杂度为O(logN)。值得注意的是,在讨论算法的时间复杂度时,logN为Base2,即如果N等于8,则logN为3。同理,虽然我们可以在O(1)时间内找到时间最小的任务,如果我们取出这个元素,内部需要调整优先级队列,这个算法的时间复杂度也是O(logN)。上面提到的时间轮法的优先级队列算法,综合算法的时间复杂度为O(logN),已经很高效了,但是在我们的大并发分布式系统中,这个速度还是太慢了。我们有更高效的算法吗?那就是时间轮算法。时间轮是一个循环队列,按照时间单位划分。我们假设1秒。每个单元内部都有一个链表,用于存储定时任务。你可能会问,毕竟循环队列中的元素是有优先级的。超过长度怎么办?我们可以想到家里的水表。它有很多轮子吗?每个轮子的单位不同。相同!时间轮也是如此。我们可以使用多级时间轮进行优化,就像我们的时钟或水表一样。一层的走一圈,下一层的只走一帧。那么,如何计算这个算法的时间复杂度呢?插入的时候,我们从下层开始查找,找出它在哪一层,然后直接插入对应的尺度。如果我们的时间轮有5层,那么我们最多搜索5次。查询的时候我们推动时间轮每秒滚动一次,每次直接取队头的元素,相当于一个O(1)的算法时间复杂度。转身时,向下推下一层的下一个格子。这样我们的一个元素就会从第五层逐渐插入到第一层最多,一个元素最多插入5次。在评估算法的时间复杂度时,我们通常会忽略常量。最终算法时间复杂度为O(1)。总结一道很简单的面试题,有几种不同的解法。这就是算法和数据结构的魅力。欢迎大家关注我,一起学习,一起进步。您的支持是我继续聊天的动力。
