我对并发编程很新,我正在学习它。
我正在Java JDK 7(Fork Join API)中实现快速排序,以对对象列表(100K)进行排序。
在不使用并发的情况下使用这段递归代码时,我发现没有内存爆炸,一切都很好。
我刚刚添加了在多核上使用它的代码(通过扩展类RecursiveAction),然后内存使用量跳得很高,直到达到极限。通过做一些分析,我观察到线程的高创建率,我认为它是可预期的。 但是,一个java线程本身对内存要求更高还是我在这里缺少一些东西?
Quicksort必须要求很多线程但不要比常规对象多。
当我达到阈值时,我是否应该停止创建RecursiveAction线程,然后切换到连续的代码片段(不再有线程)?
非常感谢。
答案 0 :(得分:3)
默认情况下,Java线程通常只占用256k / 512k(依赖于OS,jdk版本..)堆栈空间。
如果你运行的线程超过CPU密集型进程(如执行快速排序)的处理器/内核,则会浪费大量资源和速度,所以尽量不要运行比核心更多的线程。
答案 1 :(得分:0)
是的,当工作单位在ca.的范围内时,切换到顺序代码是个好主意。 10,000-100,000次操作。这只是一个经验法则。因此,为了快速排序,当要排序的大小小于10-20,000个元素时,我将退出顺序执行,具体取决于比较操作的复杂性。
ForkJoinPool的大小 - 通常它设置为创建与处理器相同数量的线程,因此您不应该看到太多线程。如果您手动将并行性设置为高(例如,数百或数千),那么您将看到高(虚拟)内存使用,因为每个线程为堆栈分配空间(默认情况下在32位Windows和Linux上为256K) 。)
答案 2 :(得分:0)
作为CPU绑定计算的经验法则,一旦您的线程数超过可用内核数,添加更多线程就不会加快速度。实际上,由于创建线程的开销,每个线程(例如线程堆栈)绑定的资源以及同步的成本,它可能会减慢您的速度。
实际上,即使您拥有无限数量的内核,也不值得创建线程来执行小任务。即使使用线程池和其他聪明的技巧,如果在任务中完成的工作量太小,使用线程的开销将超过任何节省。 (很难准确预测阈值的位置,这当然取决于任务的性质以及与平台相关的因素。)
答案 3 :(得分:0)
我改变了我的代码,到目前为止我有更好的结果。我调用了ForkJoinPool中的主线程任务,在Threads中,如果在ForkJoinPool中有比活动核心多得多的活动线程,我就不会创建更多线程。
我不通过join()方法进行同步。因此,父线程一旦创建其后代就会死亡。在调用root任务的main函数中。我等待任务完成,也就是没有更活跃的线程。它似乎工作正常,因为内存保持正常,我在顺序执行的同一段代码上获得了大量时间。
我将学到更多。
谢谢大家!