所有的步骤默认都具有backpressure
, 如果步骤中封装的计算无法跟上前序步骤输出元素的到来速率, 那么就会收到这个backpressure
作用. 这里列举了不同步骤应对它的下游的背压(backpressure)的不同的表现之处. 以下的表格提供了所有内置步骤的总览以及它们的语义.
所有的步骤一旦接受到任何它上游输出的一个失败信号,它会停止并传播这个失败信号到下游, 除非有监督的情况下它不这么做. 这个表现可以保证当失败出现时流的销毁以及清理. 失败用于建模不可恢复的情况下, 因此他们总是被最快的处理传播出去. 对于带内的普通错误处理(如 一个map失败了那么丢弃掉当前元素), 你应该使用监督支持, 或者显示的把你的元素类型包裹在一个可以表达错误或成功状态合适的容器里(如 Scala中的Try
).
自定义的组件没有被这个表格所包含, 因为它们的语义由用户自己定义.
这些步骤都可以以一个PushPullStage
来表达. 这些步骤可以转换到来元素的速率, 因为有一些步骤可以输入单个元素而输出多个(例如 mapConcat
)或者在输出一个元素前消耗了多个元素(例如 filter
). 然而这些速率的转换是数据驱动的, 也就是说是到来的元素定义如何影响速率. 这点与Backpressure
感知的步骤是不同的, Backpressure
感知的步骤会依据它们的下游背压来改变处理行为.
步骤 | 何时输出 | 何时背压 | 何时结束 |
---|---|---|---|
map | 映射函数返回结果时 | 下游产生背压 | 上游结束 |
mapConcat | 映射函数返回结果时或者上次计算的 集合还有剩余元素 | 下游产生背压或者上次计算的集合 还有剩余元素 | 上游结束并且所有剩余 的元素已经输出 |
filter | 当元素在给定的判断方法返回True时 | 当元素在给定的判断方法返回True时且 下游有背压 | 上游完成 |
collect | 提供的偏函数对该元素有定义 | 提供的偏函数对该元素有定义且 下游有背压 | 上游完成 |
grouped | 元素积累到定义的数值时 或者上游结束时 | 一个group已经组装完毕且 下游有背压 | 上游完成 |
sliding | 元素积累到定义的数值时 或者上游结束时 | 一个group已经组装完毕且 下游有背压 | 上游完成 |
scan | 定义的scan函数扫描该元素 返回一个新的元素 | 下游有背压 | 上游完成 |
fold | 上游完成 | 下游有背压 | 上游完成 |
drop | 当丢弃的元素个数和设定数值相当时 | 当丢弃元素个数和设定数值相当 且下游有背压 | 上游完成 |
take | 输出元素的个数还没有达到指定数值 | 下游有背压 | 定义的数值相当的元素 个数已经被取走或者 上游结束 |
takeWhile | 判断方法返回为True直到 出现第一个false的结果 | 下游有背压 | 判断返回为false 或者上游完成 |
dropWhile | 判断方法返回false的元素及 其后所有元素 | 判断方法返回false后 且下游有背压 | 上游完成 |
recover | 上游的元素可用或者上游 已经失败但是偏函数返回一个元素 | 在失败没有发生时 下游有背压 | 上游完成或者上游 以偏函数可以 处理的异常失败 |
detach | 上游步骤有元素输出 并且存在需求 | 下游有背压 | 上游完成 |
这些步骤封装了异步计算, 在处理异步操作的同时合理的处理好backpressure
(通常处理一个Future
的完成).
步骤 | 何时输出 | 何时背压 | 何时结束 |
---|---|---|---|
mapAsync | 由序列中的下一个元素经过 指定的函数生成的Future 返回结果时 |
并行的Future 数到达 指定数值并且下游有背压 |
上游完成并且所有 的Future 已经完成 并输出结果 |
mapAsyncUnOrdered | 任何由指定函数返回的Future 完成时 |
并行的Future 数到达 指定数值并且下游有背压 |
上游完成并且所有 的Future 已经完成 并输出结果 |
这些步骤处理使用了定时器, 延迟, 某段时间丢弃或者组合的元素.
步骤 | 何时输出 | 何时背压 | 何时结束 |
---|---|---|---|
takeWithin | 上游的元素到来时 | 下游有背压 | 上游完成或者定时器触发 |
dropWithin | 在定时器触发后且一个 新的上游元素到来时 | 下游有背压 | 上游完成 |
groupedWithin | 在最近的一个组被输出 起指定的时间后 | 组已经创建(已经超过了时间段)并且下游有背压 | 上游完成 |
现阶段无法创建自定义的时间驱动步骤
这些步骤都可以用DetachedStage
来描述. 这些步骤都可以感应下游的背压并可以根据这些信号来改变自己的行为.
步骤 | 何时输出 | 何时背压 | 何时结束 |
---|---|---|---|
conflate | 下游停止了背压并且存在 一个可用的合并元素 | 从不(除非封装的计算不够快) | 上游完成 |
expand | 下游停止了背压 | 下游有背压 | 上游完成 |
buffer(Backpressure) | 下游停止了背压并且缓存中 存在一个就绪状态的元素 | 缓存满了 | 下游完成并且缓存 的元素被抽取完毕 |
buffer(DropX) | 下游停止了背压并且缓存中 存在一个就绪状态的元素 | 从不(除非封装的计算不够快) | 下游完成并且缓存 的元素被抽取完毕 |
buffer(Fail) | 下游停止了背压并且缓存中 存在一个就绪状态的元素 | 当缓存满时使得流失败 而不是产生背压 | 下游完成并且缓存 的元素被抽取完毕 |
这些步骤是接受一个流然后转化成一个流为元素的流(嵌套)亦或接收一个嵌套流的流然后替换输出成一个包含元素的流(扁平化).
现阶段无法创建自定义的嵌套或者扁平化步骤
步骤 | 何时输出 | 何时背压 | 何时结束 |
---|---|---|---|
prefixAndTail | 存在配置个数相等的前缀元素. 输出这个前缀, 然后剩下的元素成为一个子流元素. | 下游有背压或者子流有背压 | 前缀元素被消耗并且子流被消耗 |
groupBy | 对每一个元素使用组团函数 返回新出现的组. 输出一个新组 | 一个子流有背压的组 存在一个就绪元素时 | 上游完成 |
splitWhen | 当一个元素在给定的判定函数为true时, 打开并且输出后续的元素到一个子流 | 下一个子流存在就绪元素, 但是上一个并没有 完全消耗完毕或者存在背压时 | 上游完成 |
splitAfter | 元素先通过, 一旦给定的判定函数返回true后它输出这个元素, 然后为后续元素打开一个新的子流 | 下一个子流存在就绪元素, 但是上一个并没有 完全消耗完毕或者存在背压时 | 上游完成 |
flatMap Concat | 当前消耗的子流存在可用元素 | 下游有背压 | 上游完成并且所有子流完成 |
flatMap Merge | 任一子流存在可用元素 | 下游有背压 | 上游完成并且所有子流完成 |
这里面大部分的步骤可以用GraphStage
表达. 这些步骤用多个流作为输入并提供单个输出, 它们以不同方式组合所有的输入.
现阶段自定义的扇入步骤有限制
步骤 | 何时输出 | 何时背压 | 何时结束 |
---|---|---|---|
merge | 任一输入有可用元素 | 下游有背压 | 所有的上游完成(*) |
mergeSorted | 所有的输入有一个可用元素 | 下游有背压 | 所有的上游完成 |
mergePreferred | 任一输入有可用元素, 当存在多个可用元素时 更倾向使用某一定义的输入元素 | 下游有背压 | 所有的上游完成(*) |
zip | 所有的输入都有一个可用元素 | 下游有背压 | 任一上游完成 |
zipWith | 所有的输入都有一个可用元素 | 下游有背压 | 所有的上游完成 |
concat | 当前的流有可用元素; 如果当前流完成, 它会尝试下一个流 | 下游有背压 | 所有的上游完成 |
prepend | 给定的流有可用元素; 如果给定的输入完成, 它会尝试当前的流 | 下游有背压 | 所有的上游完成 |
(*)这个行为可能因为任意的上游以eagerClose=true
的配置结束而发生改变.
这里大部分的步骤可以用GraphStage
来表达. 有一个输入和多个输出. 他们可能在不同的输出中路由元素, 或者同一时间内在多个输出上输出元素.
步骤 | 何时输出 | 何时背压 | 何时结束 |
---|---|---|---|
unzip | 所有输出都停止产生背压 并且输入有可用元素 | 任一一个输出有背压 | 上游完成 |
unzipWith | 所有输出都停止产生背压 并且输入有可用元素 | 任一一个输出有背压 | 上游完成 |
broadcast | 所有输出都停止产生背压 并且输入有可用元素 | 任一一个输出有背压 | 上游完成 |
balance | 任一输出都停止产生背压; 输出元素到第一个可用的输出 | 所有的输出有背压 | 上游完成 |