Java 使用jdk 7的新fork-join框架的性能问题

Java 使用jdk 7的新fork-join框架的性能问题,java,multithreading,performance,parallel-processing,fork-join,Java,Multithreading,Performance,Parallel Processing,Fork Join,我正在使用jdk 7的新forkjoin框架。 我有一个任务,必须用不同的参数执行多次 此任务扩展了递归任务。有100多个任务要执行,可以同时执行。任务是独立的,因此不需要任何同步。 因此,我首先创建了所需的任务,并将它们传递给forkjoin线程池。 但是应用程序的运行速度比没有任何并行性的情况下要慢 我的第一个想法是,我创造了很多线程。。这就是为什么我尝试回收线程以减少对象创建开销,但这对性能没有影响。用于使用reinitialize()方法回收im。此外,通过循环使用,性能比在没有任何并行

我正在使用jdk 7的新forkjoin框架。 我有一个任务,必须用不同的参数执行多次

此任务扩展了递归任务。有100多个任务要执行,可以同时执行。任务是独立的,因此不需要任何同步。 因此,我首先创建了所需的任务,并将它们传递给forkjoin线程池。 但是应用程序的运行速度比没有任何并行性的情况下要慢

我的第一个想法是,我创造了很多线程。。这就是为什么我尝试回收线程以减少对象创建开销,但这对性能没有影响。用于使用reinitialize()方法回收im。此外,通过循环使用,性能比在没有任何并行性的情况下运行要慢


任务中执行的操作并不简单,运行线程的持续时间为5到150毫秒。应用程序在双核机器上运行,im使用ubuntu和oracle jdk 7。

库普斯福特的爱德华·哈内德发现了Java中实现的Fork/Join设计的许多问题

特别是,“工作窃取”会遭受高竞争&在多个处理器之间分配工作效率低下。递归分解也不是特别有效

如果您的任务不是递归的——您说有100个,并且它们可以并发执行——那么使用ThreadPoolExecutor的更简单方法可能更有效

见:


CoopSoft的Edward Harned发现Java中实现的Fork/Join设计存在许多问题

特别是,“工作窃取”会遭受高竞争&在多个处理器之间分配工作效率低下。递归分解也不是特别有效

如果您的任务不是递归的——您说有100个,并且它们可以并发执行——那么使用ThreadPoolExecutor的更简单方法可能更有效

见:


您是否构建了一个简单的程序,该程序简单地分叉一个任务并等待它完成,线程不做任何工作,以了解上下文切换时间?你知道那些时间是什么吗?。。。您会注意到,使用2个处理器时,您的加速比最多为2倍。你确定你需要100个独立的任务吗?我会试试你的第一条评论:)如前所述,我不再使用100个独立的线程。我创建了固定数量的线程,这些线程是扩展RecursiveTask的对象,如许多示例所示,例如2。之后,我设置这些对象的参数,并将它们传递到池中,以便并发运行。之后,我重新设置参数,只要元素可用,就必须执行这些任务。5到150毫秒的持续时间是否不足以使用线程?与管理线程的开销相比,并行性的问题在于可以完成的工作量。如果分叉需要50毫秒,而您有50毫秒的工作要做,那么您只有50%的效率。有了两个CPU,与一个CPU相比,您最多只能希望收支平衡。所以,了解你的开销很重要。我不知道Java分叉需要这么长的时间(根本没有经验),这对我来说似乎是一个令人不安的高数字。因此建议对其进行度量。您是否构建了一个简单的程序,该程序简单地分叉一个任务并等待它完成,线程不做任何工作,以了解上下文切换时间?你知道那些时间是什么吗?。。。您会注意到,使用2个处理器时,您的加速比最多为2倍。你确定你需要100个独立的任务吗?我会试试你的第一条评论:)如前所述,我不再使用100个独立的线程。我创建了固定数量的线程,这些线程是扩展RecursiveTask的对象,如许多示例所示,例如2。之后,我设置这些对象的参数,并将它们传递到池中,以便并发运行。之后,我重新设置参数,只要元素可用,就必须执行这些任务。5到150毫秒的持续时间是否不足以使用线程?与管理线程的开销相比,并行性的问题在于可以完成的工作量。如果分叉需要50毫秒,而您有50毫秒的工作要做,那么您只有50%的效率。有了两个CPU,与一个CPU相比,您最多只能希望收支平衡。所以,了解你的开销很重要。我不知道Java分叉需要这么长的时间(根本没有经验),这对我来说似乎是一个令人不安的高数字。因此建议对其进行衡量。下面是另一篇好文章,它给出了一个更平衡的观点:。FJP的一些经验法则似乎是:1。避免使用公共池,因为JVM/库可能正在使用公共池。2.避免在线程中阻塞,因为FJP是固定大小的(仅限CPU绑定的任务)3。设置从递归切换到串行的阈值,否则可能会破坏堆栈,因为每个join()都在同一线程中运行新任务。因此,我认为FJP最适合于CPU范围内深度较浅但分支较大(即许多任务)的拆分和合并。这是另一篇好文章,它提供了一个更平衡的视图。FJP的一些经验法则似乎是:1。避免使用公共池,因为JVM/库可能正在使用公共池。2.避免在线程中阻塞,因为FJP是固定大小的(仅限CPU绑定的任务)3。设置从递归切换到串行的阈值,否则可能会破坏堆栈,因为每个join()都在同一线程中运行新任务。因此,我认为FJP最适合于CPU范围内深度较浅但分支较大的拆分和合并(即许多任务)