最佳方法:树集结构 vs 线程池执行器
Posted
技术标签:
【中文标题】最佳方法:树集结构 vs 线程池执行器【英文标题】:Best approach: tree set structure vs thread pool executor 【发布时间】:2014-11-26 07:03:20 【问题描述】:伙计们,我在Tree Set
和Thread Pool Executor
之间进退两难
以下是场景:
第一种方法
-
我必须使用其中包含任务的结构以及每个任务的优先级。现在基于
treeset constructor
(带有comparator
接口)
我可以比较任务的优先级,并据此对任务进行正确排序。
现在之后,任务应该通过树集的迭代按优先级顺序处理,并一个一个地执行每个任务。
第二种方法
-
第二种方法是进行某种逻辑构建并使用
Thread pool executor
的核心功能,为此我从this link 中获得了灵感,并且我通过这种方法实现了我的要求,它将首先选择高优先级任务,然后首先执行它,它会以同样的方式执行所有任务。
现在我的困惑是在性能成本、灵活性(增加/减少线程)等方面最好使用哪一个,我为什么要选择它?
非常感谢任何建议和答案。
【问题讨论】:
我不认为线程池优先级可以保证让那些线程先行,所以你的树集听起来更好。 我见过的大多数执行器示例都使用队列。为什么不将PriorityQueue
与相同的比较器一起使用?询问哪个是“最好的”实际上取决于您的用例和工作量,因为没有一个答案总是适用于您的特定任务。
@Evan 知道我已经制作了thread pool executor
模型的原始原型,如果您想要输出,您可以查看上面问题链接中提供的示例,其中包含主要方法示例及其输出使其更具描述性
@Makoto 我已经实施了优先队列,我得到了预期的结果,但是 M 在性能成本和灵活性方面寻找最佳解决方案
@didierc 在this link 的帮助下,我已经完成了任务排序和执行。感谢您的宝贵建议,但我很想知道treeset
和thread pool executor
之间谁比谁更好.
【参考方案1】:
您的问题中嵌入了两种不同的优先级概念:
起始优先级:任务提交执行的顺序,(第一种方法说明的第 1 点)
运行时优先级:考虑调度线程的顺序(第3点)
这两个属性在您的场景中恰好相等,因此树集将帮助您定义它们。执行器将帮助您执行它们,但您将需要一个特别定制的执行器(基于或不基于线程池),以特定优先级启动您的线程。基本上,每次从优先级队列中拉出任务时,它都应该与设置在任务优先级的线程相关联。我假设这是您链接的文章中的执行程序实现所提供的功能,因此您可以执行此操作。
关于线程池,来自文档:
使用工作线程可以最大限度地减少由于创建线程而产生的开销。线程对象使用大量内存,在大型应用程序中,分配和释放许多线程对象会产生大量内存管理开销。
工作线程是由线程池管理的线程,并且被保守地回收(与销毁和重新创建相反)以处理任务序列。我认为优先级处理并不重要,但它会优化您对资源的使用。
关于文章中的实现,代码使用一个简单的阻塞双端队列来处理传入的任务,因此它是一个普通的 fifo 优先级方案。它不会重新排序任务。
【讨论】:
正是,该特性(线程的优先级与任务的优先级相同)是在第二种方法中实现的。tree set
方法很好,但我的困惑是时间复杂度、繁重任务负载期间的性能成本、灵活性等,具体取决于选择哪一种。?
啊,对不起,我错过了这一点。我想如果没有具体的实现细节,就很难根据复杂性和成本来评估它们。【参考方案2】:
最终从这两个中获得了真正的赢家。我应该选择Thread pool Executor
,原因如下
-
性能成本:在这里,如果我们看到,使用资源最大值是在重负载期间获得性能的主要动机。因此,如果我们在这个高时间使用线程,它将提供高性能作为多线程的优势线程。
灵活性:在资源可扩展使用方面的灵活性,即在低时间我们可以减少
thread pool executor
架构中的工作线程数量,反之亦然。
迭代次数少,更新少:如果我们每次都维护树集,它会在comparator
接口的帮助下检查,虽然它有复杂度O(logn)但是之后我们必须获取它,它将成为单源的顺序流,因此我们将没有多线程环境的优势。
更快的处理:借助线程架构,我们可以实现更快的输出。
等是我在激烈的头脑风暴、谷歌搜索和最后但并非最不重要的堆栈溢出搜索中指出的原因。感谢大家对@didierc 的谦虚支持和极大的感谢,让我明白了这一点。
【讨论】:
【参考方案3】:你可以在普通线程池中尝试DelayedQueue。
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(size, size, 0, TimeUnit.DAYS, new DelayQueue<>());
threadPoolExecutor.execute(runnable);
Runnable 应该是实现 Comparable 。所以在这个实现中,优先级将由延迟队列处理。
这种方法会更容易实现。
【讨论】:
以上是关于最佳方法:树集结构 vs 线程池执行器的主要内容,如果未能解决你的问题,请参考以下文章