ReferencePipeline

用于描述中间管道阶段或者管道源阶段的抽象基类。

继承 AbstractPipeline,实现 Stream

AbstractPipeline

继承 PipelineHelper,实现 BaseStream

文档说明

  • 管道类的抽象父类,是 Stream 接口及其原生特化的核心实现。它会管理流管道的构建及评估
  • AbstractPipeline 代表一个流管道的的初始部分,它封装了流的源,以及一个或多个中间操作
    • 每个 AbstractPipeline 对象通常被称为 stage(阶段),每个阶段描述的,要么是流的源,要么是一个中间操作
  • 一个具体的中间阶段通常通过一个 AbstractPipeline 构建,一个 “类型特化(shape-specific)管道” 继承它(如:IntPipeline)后仍旧抽象,再由一个“操作特化(operation-specific)”的具体类去继承前者
  • AbstractPipeline 包含了大多数评价管道的机制,并且实现方法,这些实现的方法都会被操作使用到;“类型特化”的类会添加一些辅助方法,用于将结果集装到合适的“类型特化”的容器当中(也就是避免装箱拆箱的操作)
  • 在链接一个新的中间操作,或者执行一个终止操作后,这个流就会被标记为已消费,并且不会再有更多的中间或终止操作添加到这个流实例当中
  • implNote
  • 对于串行流,以及所有中间操作都无状态的的并行流两种情况,管道的计算是在单个的过程中完成的,所谓的单个的过程就是,将所有的操作都放到一起完成
  • 对于有状态操作的并行流,执行会被分为多个“段”,当中每个有状态的操作都会在段的结尾打上标识,然后每个段都会单独地进行计算,并且每段的输出结果都会作为下一段的输入
  • 在所有的情况中,在一个终止操作开始之前,源数据都不会被消费

属性

  • previousStage
    • 上游的 pipeline,源阶段置 null
  • sourceStage
    • 指向管道头的反指向链,源阶段为自身
  • sourceOrOpFlags
  • combinedFlags
  • depth
    • 当前管道对象与流的源(串行)或前状态(并行)之间,中间操作的个数
    • 在管道准备进行计算的时间点有效
  • parallel
    • 是否并行,只在流的源阶段有效
  • sourceSpliterator
    • 源的 spliteraror,只在管道头有效
    • 在管道被消费前,若为“非空”,则 sourceSupplier 必须为 null
    • 在管道被消费后,若为“非空”,则将其置 null
  • sourceSupplier
    • 源的 supplier,只在管道头有效
    • 在管道被消费前,若为“非空”,则 sourceSpliterator 必须为 null
    • 在管道被消费后,若为“非空”,则将其置 null

构造方法

构造方法一:构造流管道的头

上游 pipeline 置 null,将带有数据源引用的 spliterator 赋给当前 pipeline,

将当前阶段标记为源阶段,配置操作属性,当前深度初始化为0,设置 串行/并行 标记

AbstractPipeline(Supplier<? extends Spliterator<?>> source,
                     int sourceFlags, boolean parallel) {
    this.previousStage = null;
    this.sourceSupplier = source;
    this.sourceStage = this;
    this.sourceOrOpFlags = sourceFlags & StreamOpFlag.STREAM_MASK;
    // The following is an optimization of:
    // StreamOpFlag.combineOpFlags(sourceOrOpFlags, StreamOpFlag.INITIAL_OPS_VALUE);
    this.combinedFlags = (~(sourceOrOpFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE;
    this.depth = 0;
    this.parallel = parallel;
}

 

构造方法二:构造用于追加一个中间操作到一个既有的 pipeline 上

断言,若传入的上游 pipeline 已被链接过消费,则抛出异常;

将上游 pipeline 标记为已消费;将上游 pipeline 的下游指向当前 pipeline;将当前 pipeline 的上游指向上游 pipeline;

配置操作属性;深度 +1

AbstractPipeline(Spliterator<?> source,
                     int sourceFlags, boolean parallel) {
    this.previousStage = null;
    this.sourceSpliterator = source;
    this.sourceStage = this;
    this.sourceOrOpFlags = sourceFlags & StreamOpFlag.STREAM_MASK;
    // The following is an optimization of:
    // StreamOpFlag.combineOpFlags(sourceOrOpFlags, StreamOpFlag.INITIAL_OPS_VALUE);
    this.combinedFlags = (~(sourceOrOpFlags << 1)) & StreamOpFlag.INITIAL_OPS_VALUE;
    this.depth = 0;
    this.parallel = parallel;
}

 

抽象方法

abstract Sink<E_IN> opWrapSink(int flags, Sink<E_OUT> sink)

说明文档

  • 接收一个接收操作结果的 Sink,并返回一个接收当前操作的输入类型的元素并执行操作的 Sink,将结果传递到提供的 Sink 中
  • apiNote
  • 实现类可能使用 flag 参数去优化 sink 的包装
  • 例如,如果输入已经是 DISTINCT ,那么 distinct() 方法的实现只需要返回 sink

 

实现方法

wrapAndCopyInto

@Override
final <P_IN, S extends Sink<E_OUT>> S wrapAndCopyInto(S sink, Spliterator<P_IN> spliterator) {
    copyInto(wrapSink(Objects.requireNonNull(sink)), spliterator);
    return sink;
}
  • 通过 wrapSink 方法获取最初的 sink
  • 通过 copyInto 方法遍历元素
  • 循例将执行到的 sink 返回,即使没什么意义

wrapSink

@Override
@SuppressWarnings("unchecked")
final <P_IN> Sink<P_IN> wrapSink(Sink<E_OUT> sink) {
    Objects.requireNonNull(sink);

    for ( @SuppressWarnings("rawtypes") AbstractPipeline p=AbstractPipeline.this; p.depth > 0; p=p.previousStage) {
        sink = p.opWrapSink(p.previousStage.combinedFlags, sink);
    }
    return (Sink<P_IN>) sink;
}
  • 传入下一阶段的 sink,获取当前阶段的 sink,循环获取最初阶段的 sink

copyInto

@Override
final <P_IN> void copyInto(Sink<P_IN> wrappedSink, Spliterator<P_IN> spliterator) {
    Objects.requireNonNull(wrappedSink);

    if (!StreamOpFlag.SHORT_CIRCUIT.isKnown(getStreamAndOpFlags())) {
        wrappedSink.begin(spliterator.getExactSizeIfKnown());
        spliterator.forEachRemaining(wrappedSink);
        wrappedSink.end();
    }
    else {
        copyIntoWithCancel(wrappedSink, spliterator);
    }
}
  • 判断是否有短路操作(filter 之类的中间操作)
  • 遵循 Sink 中定义的操作顺序调用遍历方法,最终调用数据源的 tryAdvance方法

 

ReferencePipeline.Head

表示 ReferencePipeline 的源阶段

继承了 ReferencePipeline(二者在大部分属性的设定上是类似的,但存在一些属性是不同的,比如说 Head 的 previousStage 是空的,而 ReferencePipeline 则存在 previousStage,等等)

构造方法

本质上是调用的是 AbstractPipeline 的构造方法一,

ReferencePipeline(Supplier<? extends Spliterator<?>> source, int sourceFlags, boolean parallel) {
    super(source, sourceFlags, parallel);
}
ReferencePipeline(Spliterator<?> source, int sourceFlags, boolean parallel) {
    super(source, sourceFlags, parallel);
}

ReferencePipeline.StatelessOp

一个基类,针对一个流的无状态的中间阶段,同样集成了 ReferencePipeline

构造方法

本质上调用的是 AbstractPipeline 的构造方法二

StatelessOp(AbstractPipeline<?, E_IN, ?> upstream, int opFlags) {
    super(upstream, opFlags);
    assert upstream.getOutputShape() == inputShape;
}

 

posted @ 2019-09-16 23:36  飞蛇在水  阅读(1834)  评论(0编辑  收藏  举报