模拟具有固定工作量的CPU密集型任务

时间:2016-01-11 16:24:18

标签: java multithreading threadpool throughput

我正在模拟CPU绑定任务。每个CPU绑定任务计算因子800.每个CPU绑定任务是由Thread执行的Runnable对象。当我增加线程数(每个线程运行一个Runnable tak)然后我发现一些线程以如此快的速度运行,使得服务时间趋于零。我无法理解这种行为。代码如下。

import java.math.BigInteger;    
public class CpuBoundJob  implements Runnable {     
    public void run() {    
         BigInteger factValue = BigInteger.ONE;
            long t1=System.nanoTime();      
            for ( int i = 2; i <= 800; i++){
              factValue = factValue.multiply(BigInteger.valueOf(i));
            }
        long t2=System.nanoTime();              
        System.out.println("Service Time(ms)="+((double)(t2-t1)/1000000));
    }    
}
public class TaskRunner extends Thread {
    CpuBoundJob job=new CpuBoundJob();
    public void run(){

    job.run();  
    }
}
public class Test {
int numberOfThreads=5;
public Test(){
    for(int i=1;i<=numberOfThreads;i++){
        TaskRunner t=new TaskRunner();
        t.start();
        }
}
public static void main(String[] args) {
    new Test(); 
    }
}

如果是5个螺纹,则输出如下。

Service Time(ns)=28.765821
Service Time(ns)=33.489663
Service Time(ns)=29.19727
Service Time(ns)=34.259404
Service Time(ns)=37.347448

如果是10个螺纹,则输出如下。

Service Time(ns)=45.647232
Service Time(ns)=3.972654
Service Time(ns)=23.494475
Service Time(ns)=12.210069
Service Time(ns)=19.382478
Service Time(ns)=15.34706
Service Time(ns)=54.769652
Service Time(ns)=20.646827
Service Time(ns)=3.28936
Service Time(ns)=29.809905
Service Time(ns)=60.798897
Service Time(ns)=50.718839
Service Time(ns)=2.727253
Service Time(ns)=2.882779
Service Time(ns)=63.864835
Service Time(ns)=42.601425
Service Time(ns)=4.029496
Service Time(ns)=4.339761
Service Time(ns)=79.396239
Service Time(ns)=2.923832
Service Time(ns)=5.773848
Service Time(ns)=3.064359
Service Time(ns)=2.446592
Service Time(ns)=2.205802
Service Time(ns)=2.212513
Service Time(ns)=2.265408
Service Time(ns)=82.51073
Service Time(ns)=2.200276
Service Time(ns)=2.289487
Service Time(ns)=2.322645
Service Time(ns)=2.201459
Service Time(ns)=2.217644
Service Time(ns)=2.197908
Service Time(ns)=2.252381
Service Time(ns)=13.564814
Service Time(ns)=2.238171
Service Time(ns)=2.199486
Service Time(ns)=2.179355
Service Time(ns)=2.237381
Service Time(ns)=2.593041
Service Time(ns)=2.444225
Service Time(ns)=2.42054
Service Time(ns)=38.745219
Service Time(ns)=81.232565
Service Time(ns)=19.612216
Service Time(ns)=22.31381
Service Time(ns)=59.521916
Service Time(ns)=59.511258
Service Time(ns)=54.439255
Service Time(ns)=11.582434

我无法理解2.4等的服务时间,有时服务时间下降到0.8。为什么运行固定工作量的线程执行速度如此之快?

3 个答案:

答案 0 :(得分:2)

你是如何开始这些测试的?如果你每次都开始冷启动,我怀疑JVM是“warming up”和Just In Time compiling代码。如果是这种情况,带有几个线程的测试将作为解释代码运行,后续运行将被编译,甚至以后的运行也会根据以前的运行进行优化。 The JVM is magic that way

使优化不太可能发生的想法:

  • 使用随机数作为工作参数(而不是循环索引)
  • 将时间用作工作参数(同上)
  • 抛出一些字符串连接
  • 使用工作参数
  • 改变循环的长度

答案 1 :(得分:1)

在某些时候,JIT可能会启动并优化代码。尝试运行实验首先“预热”系统,即N次迭代(你需要试验N的良好值)运行系统而不进行测量 - 然后测量例如:

public class Test {

private int numberOfThreads;
private int warmUpIterations;

public Test(int numberOfThreads, int warmUpIterations) {
    this.numberOfThreads = numberOfThreads;
    this.warmUpIterations = warmUpIterations;
}

public void runTests() {
    for (int i = 0; i < warmUpIterations; i++) {
        test(); // don't collect timing here
    }

    test(); // collect timing here
}

private void test() {
    for (int i = 0; i < numberOfThreads; i++) {
        TaskRunner t = new TaskRunner();
        t.start();
    }
}

public static void main(String[] args) {
    new Test(10, 10000).runTests();
}

}

同时打印run()内的统计信息是有问题的,请考虑在某些集合中累积它们并在测试完成后打印它们。

答案 2 :(得分:0)

很可能定时功能太不准确,无法测量这种快速操作。尝试100000或类似的阶乘。

nanotime方法的文档说它无法保证提供纳秒精度:

  

此方法提供纳秒级精度,但不一定是纳秒级分辨率(即,值的变化频率) - 除了分辨率至少与currentTimeMillis()的分辨率一样好之外,不做任何保证。