使用流级联与并行性来展平层次结构

时间:2018-04-16 15:00:33

标签: java parallel-processing java-stream hierarchy

考虑以下类,它表示父子单向层次结构中的单个节点:

public class Component {

  private final int value;
  private final List<Component> children;

  public Component(int value) {
    this.value = value;
    this.children = new ArrayList<>();
    System.out.println("Created: " + this);
  }

  public Component child(Component child) {
    this.children.add(child);
    return this;
  }

  public Stream<Component> asFlatStream() {
    return Stream.concat(Stream.of(this),
        children.stream().flatMap(Component::asFlatStream));
  }

  public List<Component> asFlatList() {
    List<Component> flat = new ArrayList<>();
    return asFlatListInternal(flat);
  }

  public List<Component> asFlatListInternal(List<Component> flat) {
    flat.add(this);
    for (Component child : children) {
      child.asFlatListInternal(flat);
    }
    return flat;
  }

  @Override
  public String toString() {
    return String.valueOf(value);
  }

  public static void main(String[] args) {
    Component root = new Component(0)
        .child(new Component(1)
            .child(new Component(5))
            .child(new Component(6))
            .child(new Component(7)
                .child(new Component(8))))
        .child(new Component(2)
            .child(new Component(9))
            .child(new Component(10)))
        .child(new Component(3))
        .child(new Component(4));

    Supplier<Stream<Component>> streamSupplier = () -> root.asFlatStream();
    System.out.print("Sequential as stream: ");
    streamSupplier.get()
        .peek(c -> System.out.print(c + " "))
        .forEach(c -> { });
    System.out.print("\n  Parallel as stream: ");
    streamSupplier.get().parallel()
        .peek(c -> System.out.print(c + " "))
        .forEach(c -> { });

    System.out.print("\n  Sequential as list: ");
    root.asFlatList().stream()
        .peek(c -> System.out.print(c + " "))
        .forEach(c -> { });
    System.out.print("\n  Parallel as list: ");
    root.asFlatList().stream().parallel()
        .peek(c -> System.out.print(c + " "))
        .forEach(c -> { });
  }

}

运行的可能输出:

Created: 0
Created: 1
Created: 5
Created: 6
Created: 7
Created: 8
Created: 2
Created: 9
Created: 10
Created: 3
Created: 4
Sequential as stream: 0 1 5 6 7 8 2 9 10 3 4 
  Parallel as stream: 1 5 6 7 8 2 0 9 10 3 4 
  Sequential as list: 0 1 5 6 7 8 2 9 10 3 4 
    Parallel as list: 2 9 8 10 1 0 7 6 4 3 5

对几个连续运行的观察:

  1. 组件始终以相同的顺序创建:预期
  2. 基于流和基于列表的展平算法的顺序处理顺序始终相同:预期
  3. 基于列表的展平算法的并行处理顺序各不相同:预期
  4. 基于流的展平算法的并行处理顺序几乎总是相同,只是略微不同于任何顺序处理结果所观察到的顺序:不期望 。我认为这也应该像(3)那样变化。
  5. 为简洁起见,我使用的示例进行了简化,我在具有数百个组件和实际处理逻辑的实际应用程序中观察到相同的行为(每个块都是非空的)。

    在真实的应用程序中,我给偷看时间戳并为平均持续1-2秒的每个块实现了一个但仍然没有重叠,但他们总是等待前一个完成建议没有发生实际的并行处理。我还尝试了各种线程池大小,它是我拥有的核心数量的2到2倍,但没有任何效果。

    将实际应用程序的运行时间减少到1/3的唯一解决方案让我对实际使用并行性的信心是从基于流的扁平化算法切换到基于列表的算法。

    我对(4)的期望是否错误,如果没有,对行为的解释是什么?或者基于流的展平算法是否被破坏,如果是,那么它的修复是什么?

0 个答案:

没有答案