Java 为什么使用Executor的并行编程的加速比内核还要快?

Java 为什么使用Executor的并行编程的加速比内核还要快?,java,parallel-processing,executorservice,parallelism-amdahl,Java,Parallel Processing,Executorservice,Parallelism Amdahl,我正在编写一个使用Executorservice框架处理矩阵并行编程的程序。我将fixedpoolsize设置为4,但让我惊讶的是,当矩阵维度设置为5000时,使用多线程处理串行执行的加速比大于4(这也是我的CPU核心)。我已经检查过我的CPU不支持超线程 实际上,我使用可调用和未来容器,因为我的多线程任务要求返回结果 //用于并行编程的部分代码 double[]x=新的double[N][N]; List futureList=新建ArrayList(); 对于(int k=0;k=0;i-

我正在编写一个使用Executorservice框架处理矩阵并行编程的程序。我将fixedpoolsize设置为4,但让我惊讶的是,当矩阵维度设置为5000时,使用多线程处理串行执行的加速比大于4(这也是我的CPU核心)。我已经检查过我的CPU不支持超线程

实际上,我使用可调用和未来容器,因为我的多线程任务要求返回结果


//用于并行编程的部分代码
double[]x=新的double[N][N];
List futureList=新建ArrayList();
对于(int k=0;k=0;i--)
{
双和=0;
对于(int j=i+1;j

//串行编程的部分代码
double[]x=新的double[N][N];
对于(int k=0;k=0;i--)
{
双和=0;
对于(int j=i+1;j
简而言之,我只是将内部循环拿走,让线程运行它,而保持外部循环不变

但是加速怎么会是这样呢


从我之前的概念来看,最大加速比只能是4。我已经检查了这个任务实际上是由4个线程完成的。

线程可以在同一个cpu上使用。执行多线程应用程序不需要多核处理器

将线程视为一个小进程,它由父程序创建,一旦完成就被销毁。即使是单cpu计算机也可以同时运行多个线程

ExecutorService
调度要执行的线程,并在包括内核在内的可用资源范围内运行尽可能多的并行线程

以下是
fixedThreadPool

公共静态执行器服务newFixedThreadPool(int-nThreads)

创建一个线程池,该线程池重用固定数量的操作线程 离开共享的无界队列。在任何时候,最多读取个线程 将是活动的处理任务。如果提交了其他任务 当所有线程都处于活动状态时,它们将在队列中等待,直到 线程是可用的。如果任何线程在运行期间由于故障而终止 在关闭前执行,如果需要,将替换一个新的 执行后续任务。池中的线程将一直存在到 它是显式关闭的

您也可以尝试
workStealingPool

公共静态执行器服务newWorkStealingPool()

创建一个 使用所有可用处理器作为其目标的工作线程池 并行级别


这可能是CPU缓存关联的影响。如果每个核心都处理问题的不同部分,则可以提高缓存使用效率。因为RAM的速度比缓存慢10倍或更多,所以这会产生巨大的差异

您写道:“针对串行执行使用多线程的加速比大于4”-Q1)您如何衡量加速比?Q2)哪里有完全可复制的MCVE代码来再次重复此类测量?如上所述,首先要做的是确保它不是测量误差。请看,我将这两个程序封装为两个函数,并在主程序中调用它们。实际上,我每次只调用其中一个@user3666197Q2)哪里有一个完全可复制的MCVE代码来再次重复这样的测量?(如完成此操作并发布具有完全可复制(即,确实正在工作)MCVE代码状态的更新链接?)但如果操作使用100%的CPU,则添加更多线程不会加快任何速度。这是正确的,但OP没有提及其CPU以百分比运行的情况
ExecutorService
将根据当前的CPU利用率/可用资源安排线程执行。鉴于这是一个纯数学计算,我希望CPU得到充分利用。这一切都取决于可用的CPU和资源。它可以利用100%,也可以不利用100%。我检查CPU,当代码与多线程部分通信时,CPU利用率接近100%,实际上我的困惑是,我在theadpool中只为4个内核定义了4个线程,但加速比怎么可能超过4?这是所谓的“超线性加速”现象吗?我检查了导致超线性加速的潜在原因,和你刚才提到的一样。是的,当然,如果不做一些比较严格的分析,很难说出真正的原因是什么。理想情况下,您可以使用CPU跟踪,或者如果您是一个真正的硬件逻辑分析仪。没有比这更好的了!:)
// Part of code for parallel programming   

   double[][] x = new double[N][N];
    List<Future<double[]>> futureList = new ArrayList<>(); 
    for (int k=0;k<N;k++)
    {
        Future<double[]>temp=service.submit(new Thread.Task(N,k,matrix,vector));
        futureList.add(temp);  
    }
    for (int j = 0; j < N; j++) {
           x[j]=futureList.get(j).get(); 
    }

     public double[] call() throws Exception {
        for (int i = N - 1; i >= 0; i--)  
        {
            double sum = 0;
            for (int j = i + 1; j < N; j++)  
            {
                sum += matrix[i][j] * x[j];   
            }
            x[i] = (vector[i][k] - sum) / matrix[i][i]; 
        }
        return x;
    }
 // Part of code for Serial programming

    double[][] x = new double[N][N]; 
    for (int k=0;k<N;k++)
    {
        for (int i = N - 1; i >= 0; i--)  
        {
            double sum = 0;
            for (int j = i + 1; j < N; j++)  
            {
                sum += matrix[i][j] * x[j][k];   
            }
            x[i][k] = (vector[i][k] - sum) / matrix[i][i]; 
        }

    }