Java多线程:性能测试

Java多线程:性能测试,java,multithreading,Java,Multithreading,我在LinuxUbuntu18.04下有一个16核的Ryzen处理器,我想用java线程测试它。我对演出有点失望。我的期望是parralel的计算速度要快得多,但只有1秒+几毫秒的差异 那么,假设我的线程不受多个内核的支持?我的小测试不使用任何同步。它只是计算每个矩阵元素。是否有任何jvm优化,或者我需要一些参数来运行java程序 以下是我的资料来源: public class Image2DInput <T> { public static Integer[] dimensi

我在LinuxUbuntu18.04下有一个16核的Ryzen处理器,我想用java线程测试它。我对演出有点失望。我的期望是parralel的计算速度要快得多,但只有1秒+几毫秒的差异

那么,假设我的线程不受多个内核的支持?我的小测试不使用任何同步。它只是计算每个矩阵元素。是否有任何jvm优化,或者我需要一些参数来运行java程序

以下是我的资料来源:

public class Image2DInput <T> {

  public static Integer[] dimension(Integer d0, Integer d1) {
    return new Integer[] {d0, d1};
  }

  public static Integer[] point(Integer i, Integer j) {
    return new Integer[] {i, j};
  }

  public static <T> T origin(T origin) {
    return origin;
  }

  private final T origin;
  private final BiFunction<Integer[], T, T> delta;
  private final Object[][] matrix;

  public Image2DInput(
      Integer[] dimension, 
      T origin, 
      BiFunction<Integer[], T, T> delta)
  {
    throwIfNull(dimension, "origin must not be null");
    throwIfNull(origin, "origin must not be null");
    throwIfNull(delta, "deltaFunction must not be null");
    this.origin = origin;
    this.delta = delta;
    this.matrix = new Object[dimension[0]][dimension[1]];

    if (dimension[0] > 0 && dimension[1] > 0) {
      setMatrix();
      setOrigin();
    }
  }

  private void setOrigin () {
    var d0 = matrix.length / 2;
    var d1 = matrix[0].length / 2;
    this.matrix[d0][d1] = origin;
  }

  private void setMatrix () {
    var numberOfThreads = Runtime.getRuntime().availableProcessors();
    var threads = IntStream
      .range(0, numberOfThreads)
      .mapToObj( index -> new RowWorker(index, numberOfThreads) )
      .collect(Collectors.toList());
    threads.stream().forEach( t -> t.start() );
    threads.stream().forEach( t -> join(t) );
  }

  private void setSingleThreadedMatrix () {
    for (var i=0; i<matrix.length; ++i)
      for (var j=0; j<matrix[0].length; ++j)
        matrix[i][j] = delta.apply(new Integer[]{i,j}, origin);
  }


  private class RowWorker extends Thread {
    private Integer id;
    private Integer offset;

    RowWorker(Integer id, Integer offset) {
      this.id = id;
      this.offset = offset;
      setPriority(Thread.MAX_PRIORITY);
    }

    @Override
    public void run () {
      for (var i=id; i<matrix.length; i+=offset)
        for (var j=0; j<matrix[0].length; ++j)
          matrix[i][j] = delta.apply(new Integer[]{i,j}, origin);
    }
  }


  @Override
  public String toString () {
    var image = new StringBuilder();
    for (var i=0; i<matrix.length; ++i)
      writeRow (i, image);
    return image.toString();
  }

  private void writeRow (int i, StringBuilder image) {
    for (var j=0; j<matrix[0].length; ++j)
      image.append(at(i,j)).append(", ");
    image.replace(image.length()-2, image.length(), "\n");
  }

  private T at(int i, int j) {
    return (T) matrix[i][j];
  }
}
下面是我的测试运行:

  @Test
  public void testPerformance () {
    final var dim = dimension(4*2560,4*1440);
    complexImage(dim, z(0.0,0.0), (p,o) -> compute(dim, p, o));
  }

  private Complex compute (Integer[] dim, Integer[] pt, Complex origin) {
    var originAt = point(dim[0] /2, dim[1] /2);
    var offset = 1.0;
    return 
      z( (pt[1]-originAt[1])*offset, -(pt[0]-originAt[0])*offset )
      .add(origin);
  }

  private String complexImage (
      Integer[] dimension, 
      Complex origin, 
      BiFunction<Integer[], Complex, Complex> delta)
  {
    var image = new Image2DInput<Complex>(dimension, origin, delta);
    return image.toString();
  }

我已更改为FixedThreadPool。我看不出有什么不同

  private void setMatrix () {
    var numberOfThreads = Runtime.getRuntime().availableProcessors();
    var service = Executors.newFixedThreadPool(numberOfThreads);
    IntStream
      .range(0, numberOfThreads)
      .forEach( id -> service.submit( () -> {
        for (var i=id; i<matrix.length; i+=numberOfThreads)
          for (var j=0; j<matrix[0].length; ++j)
            matrix[i][j] = delta.apply(new Integer[]{i,j}, origin);
        } ));

    try {
      service.shutdown();
      service.awaitTermination(60, TimeUnit.SECONDS);
    } catch (Exception ex) {}
  }

这段代码看起来效率非常低,例如,在“性能”代码中不应该看到新的整数[],而且还缺少预热和合理的计时。我不认为这些基准特别有用。我强烈怀疑您正在计时的是32个线程的创建。同意Boris的观点,线程初始化是昂贵的,最好通过java.util.concurrent.ExecutorsNewfixedThreadPool使用线程池,并在run methodsInteger中计算时间?这不是由编译器优化的吗?我用它是出于一般的原因。。。我用then代替FixedThreadPool,得到了相同的结果。16个线程比单线程快一秒?顺便提一下我删除了toString方法调用。再快一秒钟也没什么意义。重要的是时间随着什么因素变化。如果一秒钟对应于16的加速系数,那就太大了。如果它比这个小得多,那就不算大了。然而,我猜您的算法是内存有限的,几乎所有的时间都花在访问内存上。因此,当您并行化它时,您不会看到任何显著的性能改进。谢谢您的提示。是的,它被限制在记忆中。线程一直在向矩阵写入数据。有更好的方法吗?比如,先计算,然后在计算之后,立即写入内存?