java threads vs java进程性能下降

时间:2011-08-01 14:28:55

标签: java multithreading multicore

在这里,我将重点关注自我降级的自定义应用程序(无需对线程的快速性进行一般性讨论)。

我在Java上有MPI应用程序,它使用迭代方法解决了一些问题。应用程序的示意图如下所示,我们称之为MyProcess(n),其中“n”是进程数:

double[] myArray = new double[M*K];

for(int iter = 0;iter<iterationCount;++iter)
{
   //some communication between processes

   //main loop
   for(M) 
     for(K)
     {
        //linear sequence of arithmetical instructions
     }

   //some communication between processes
}

为了提高性能,我决定使用Java线程(我们称之为MyThreads(n))。代码几乎相同 - myArray变成矩阵,其中每行包含适当线程的数组。

double[][] myArray = new double[threadNumber][M*K];


public void run()
{
  for(int iter = 0;iter<iterationCount;++iter)
  {
     //some synchronization primitives

     //main loop
     for(M) 
       for(K)
       {
          //linear sequence of arithmetical instructions

          counter++;
       }

     // some synchronization primitives
  }
}

使用Executors.newFixedThreadPool(threadNumber)创建和启动的线程。

问题在于,对于MyProcess(n),我们获得了足够的性能(在[1,8]中为n),如果MyThreads(n)性能本质上下降(在我的系统上因子为n)。

硬件:英特尔(R)Xeon(R)CPU X5355(2个处理器,每个4核)

Java版本:1.5(使用d32选项)。

起初我认为在线程上有不同的工作负载,但是,变量“计数器”显示,不同运行的MyThreads(n)之间的迭代次数([1,8]中的n)是相同的。

并且它不是同步错误,因为我有临时注释所有同步原语。

任何建议/想法将不胜感激。

感谢。

1 个答案:

答案 0 :(得分:0)

我在你的代码中看到了两个问题。


首先是缓存问题。既然你试图在多线程/进程中这样做,我会假设你的M * K结果很多;然后当你做

    double[][] myArray = new double[threadNumber][M*K];

你实际上是在创建一个大小为threadNumber的双指针数组;每个都指向一个大小为M * K的双数组。这里有趣的一点是,数组的threadNumber数不一定分配到同一块内存中。它们只是双指针,可以在JVM堆中的任何位置分配。因此,当多个线程运行时,您可能会遇到大量缓存未命中,并且最终会多次读取内存,最终会降低程序速度。

如果以上是根本原因,您可以尝试扩大JVM堆大小,然后执行

    double[] myArray = new double[threadNumber * M * K];

让线程在同一个数组的不同段上运行。你应该能够更好地看到性能。


其次是同步问题。请注意,double(或任何原始)数组不是volatile。因此,不保证您在1个线程上的结果对其他线程可见。如果您使用同步块,则可以解决此问题,因为同步的副作用是确保跨线程的可见性;如果没有,当您正在读取和写入数组时,请始终确保使用Unsafe.putXXXVolatile()和Unsafe.getXXXVolatile(),以便您可以对数组执行volatile操作。

为了更进一步,还可以使用Unsafe创建连续的内存段,您可以使用它来保存数据结构并获得更好的性能。在你的情况下,我认为1)已经做到了。