对象列表与消费者之间的性能差异

时间:2014-12-24 18:49:58

标签: java list lambda iteration

我有这种方法,生成一些点并添加到新列表中。这样做的缺点是每次都会产生太多的物体。

现在,我想回到点消费者的消费者,比如:

PointConsumer { void apply(int x, int y); }
PointIterator { void apply(PointConsumer pc); }

每当我生成一个点时,我会将一个新的lambda与旧的lambda连接起来:

pointIterator = pc -> { pointIterator.apply(pc); pc.apply(x, y); }

这种方法比前一种方法更慢还是更多内存消费者?如果差异更大或更小,请不要理会。

1 个答案:

答案 0 :(得分:5)

这是一个JMH基准,我从你非常普遍的问题中理解为你的想法。我希望它可以帮助您对所提出的效率做出一些结论。

@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode(Mode.AverageTime)
@OperationsPerInvocation(Measure.SIZE)
@Warmup(iterations = 5, time = 100, timeUnit=MILLISECONDS)
@Measurement(iterations = 5, time = 200, timeUnit=MILLISECONDS)
@State(Scope.Thread)
@Threads(1)
@Fork(1)
public class Measure
{
  public static final int SIZE = 1;
  private static final int LIMIT = 50;

  interface PointConsumer { void apply(int x, int y); }
  interface PointIterator { void apply(PointConsumer pc); }

  PointIterator pointIterator;
  List<Point> points;

  @Setup public void setup() {
    pointIterator = pc -> {};
    range(0,LIMIT).forEach(x -> range(0,LIMIT).forEach(y -> {
      final PointIterator pi = pointIterator;
      pointIterator = pc -> { pi.apply(pc); pc.apply(x, y); };
    }));
    points = range(0,LIMIT).mapToObj(i->i).flatMap(
        x -> range(0,LIMIT).mapToObj(y -> new Point(x,y)))
        .collect(toList());
  }

  @Benchmark public int pointIterator() {
    final int sum[] = {0};
    pointIterator.apply((x,y) -> sum[0] += x + y );
    return sum[0];
  }

  @Benchmark public int list() {
    int sum = 0;
    for (Point p : points) sum += p.x + p.y;
    return sum;
  }
}

测量结果:

Benchmark                    Mode  Samples   Score   Error  Units
o.s.Measure.list             avgt        5   3,921 ± 0,408  us/op
o.s.Measure.pointIterator    avgt        5  17,970 ± 1,740  us/op

我的结论:

  1. 显然,它比普通ArrayList方法慢;
  2. 创建相同数量的对象(由lambda关闭的词法环境保存在对象中);
  3. 您的设计会产生递归评估,即使是适度的列表大小,也会炸毁堆栈。