Data structures 允许有效优先级更新的优先级队列?

Data structures 允许有效优先级更新的优先级队列?,data-structures,timeout,queue,scheduling,priority-queue,Data Structures,Timeout,Queue,Scheduling,Priority Queue,更新:这里是。如果您有改进性能和并发性的想法,请告诉我。(2009年1月20日) //示例用法: 公共静态void main(字符串[]args)引发异常{ 计时器计时器=新的HashedWheelTimer(); 对于(int i=0;i

更新:这里是。如果您有改进性能和并发性的想法,请告诉我。(2009年1月20日)

//示例用法:
公共静态void main(字符串[]args)引发异常{
计时器计时器=新的HashedWheelTimer();
对于(int i=0;i<100000;i++){
timer.newTimeout(newtimertask(){
公共无效运行(超时)引发异常{
//再延长一秒钟。
timeout.extend();
}
},1000,时间单位为毫秒);
}
}
更新:我通过使用解决了这个问题。(19-01-2009)

我正在尝试用Java实现一个专用计时器,它针对超时处理进行了优化。例如,用户可以使用死线注册任务,计时器可以在死线结束时通知用户的回调方法。在大多数情况下,注册的任务将在很短的时间内完成,因此大多数任务将被取消(例如task.cancel())或重新安排到未来(例如task.rescheduleToLater(1,TimeUnit.SECOND))

我想使用此计时器检测空闲套接字连接(例如,在10秒内未收到消息时关闭连接)和写入超时(例如,在30秒内未完成写入操作时引发异常)。在大多数情况下,不会发生超时,客户端将发送消息并发送响应,除非出现奇怪的网络问题

我不能使用java.util.Timer或java.util.concurrent.ScheduledThreadPoolExecutor,因为它们假定大多数任务都应该超时。如果任务被取消,则被取消的任务将存储在其内部堆中,直到调用ScheduledThreadPoolExecutor.purge(),这是一个非常昂贵的操作。(O(NlogN)也许?)

在我在CS类中了解到的传统堆或优先级队列中,更新元素的优先级在许多情况下是一个昂贵的操作(O(logN),因为它只能通过删除元素并使用新的优先级值重新插入元素来实现。有些堆(如Fibonacci堆)具有O(1)时间decreaseKey()和min()操作,但我至少需要快速递增key()和min()(或递减key()和max())


你知道有哪种数据结构针对这个特定的用例进行了高度优化吗?我想到的一种策略就是将所有任务存储在一个哈希表中,并每隔一秒钟左右迭代所有任务,但它并没有那么漂亮。

你对队列中的项目数量有一个严格的限制-TCP套接字有一个限制


因此问题是有限的。我怀疑任何聪明的数据结构都会比使用内置类型慢。

是否有充分的理由不使用java.lang.PriorityQueue?不删除()处理日志中的取消操作(N)时间?然后根据项目在队列前面的等待时间来实现您自己的等待。

我认为最好将所有任务存储在一个列表中并反复执行


您必须(准备)在某台相当结实的机器上运行服务器,以达到成本非常重要的极限?

如何尝试将快速完成的正常情况与错误情况分开处理

使用哈希表和优先级队列。当任务启动时,它会被放入哈希表中,如果它很快完成,它会在O(1)时间内被删除

每隔一秒钟扫描一次哈希表,任何已经很长时间(例如.75秒)的任务都会移动到优先级队列。优先级队列应始终较小且易于处理。这假设1秒远小于您要查找的超时时间

如果扫描哈希表太慢,您可以使用两个哈希表,基本上一个用于偶数秒,另一个用于奇数秒。当任务启动时,它被放入当前哈希表中。每秒将所有任务从非当前哈希表移动到优先级队列中,并交换哈希表,以便当前哈希表sh表现在为空,非当前表包含1到2秒前启动的任务


有比使用优先级队列复杂得多的选项,但它们很容易实现,而且应该是稳定的。

哈希和O(logN)结构的一些组合应该满足您的要求

我很想对你分析问题的方式吹毛求疵


因为更新将非常频繁。假设我们每个连接发送M条消息,那么总时间将变为O(MNlogN),这相当大。-Trustin Lee(6小时前)

就目前而言,这是绝对正确的。但我认识的大多数人都会关注每条消息的成本,他们的理论是,随着你的应用程序有越来越多的工作要做,显然它将需要更多的资源

因此,如果您的应用程序同时打开了10亿个套接字(这真的有可能吗?),则插入成本仅为每条消息60次比较

我敢打赌,这是过早的优化:您还没有使用CodeAnalyst或VTune等性能分析工具实际测量系统中的瓶颈

不管怎么说,一旦你决定没有一个单一的结构能满足你的要求,并且你想要不同算法的优缺点的某种组合,那么你可能会有无数种方法来满足你的要求

一种可能性是将套接字域N划分为若干个大小为B的bucket,然后将每个套接字散列为其中一个(N/B)bucket更新时间。如果N的上限不是预先确定的,而是可以变化的,那么您可以动态创建更多的bucket,这会增加一点复杂性,但肯定是可行的

在最坏的情况下,看门狗定时器必须进行搜索(
// Sample usage:
public static void main(String[] args) throws Exception {
    Timer timer = new HashedWheelTimer();
    for (int i = 0; i < 100000; i ++) {
        timer.newTimeout(new TimerTask() {
            public void run(Timeout timeout) throws Exception {
                // Extend another second.
                timeout.extend();
            }
        }, 1000, TimeUnit.MILLISECONDS);
    }
}