scala flatMap或过滤哪一个更便宜

igx*_*igx 1 scala flink-streaming

我想使用键控流,我想知道哪种方法在高吞吐量方面更好让我说我有以下内容

trait A{
  val id: Int 
  def isFoo: Boolean
}
case class Foo(id: Int) extends A{
  override def isFoo = true
}
case class Bar(id: Int) extends A{
  override def isFoo = false
}
val as = List[A](Foo, Bar)
val fs: List[Foo] = as.flatMap{
  case Foo => Some(Foo)
  case _ => None
}
Run Code Online (Sandbox Code Playgroud)

我可以拥有以下流

val src: DataStream[A] = env.fromElements(as:_*)
Run Code Online (Sandbox Code Playgroud)

我有这些选择:

  1. src.filter(_.isFoo).keyBy(_.id).map(...more processing...)
  2. src.filter(_.isInstanceOf[Foo]).keyBy(_.id).map(...more processing...)//here we can remove the isFoo method
  3. src.flatMap{ case f:Foo => Some(f) case _ => None }.keyBy(_.id).map(...more processing...) 我有选项3的唯一原因是允许我从特征本身中删除id字段,Bar因为它将创建一个Foo更直接的流.然而,按字段过滤似乎比在高吞吐量下专门映射要轻得多.你怎么看 ?

Tra*_*own 14

简短回答:几乎可以肯定无关紧要,浪费你的时间来担心这些特定的编写过滤操作的方法最快.该...more processing...部分几乎肯定会成为您应用程序的瓶颈,您应该编写最清晰,最易于维护的过滤器版本.

稍微长一点的答案:即使这是某种奇怪的情况,其中一个选项明显优于其他选项,实际上影响了应用程序的性能,你最好为自己的特定情况编写自己的基准测试而不是要求Stack Overflow上的陌生人推测你的用例.

如果你真的想在Stack Overflow一个陌生人来揣测一下你的使用情况下,有一件事我要说的是,flatMap-ing成Option可能不是最好的选择在这里,因为它会导致很多不必要的分配.这是一些替代实现的超快速基准(使用Vector而不是Flink,所以使用一些盐的结果):

import org.openjdk.jmh.annotations._

@State(Scope.Thread) class FilterBenchmark {
  val values: Vector[A] = (0 to 100).map {
    case i if i % 2 == 0 => Foo(i)
    case i => Bar(i)
  }.toVector

  @Benchmark def withIsFoo: Vector[A] = values.filter(_.isFoo)

  @Benchmark def withIsInstanceOf: Vector[A] = values.filter(_.isInstanceOf[Foo])

  @Benchmark def withFlatMap: Vector[A] = values.flatMap {
    case f @ Foo(_) => Some(f)
    case _ => None
  }

  @Benchmark def withFlatMapTypeMatch: Vector[A] = values.flatMap {
    case f: Foo => Some(f)
    case _ => None
  }

  @Benchmark def withCollect: Vector[A] = values.collect {
    case f @ Foo(_) => f
  }

  @Benchmark def withCollectTypeMatch: Vector[A] = values.collect {
    case f: Foo => f
  }
}
Run Code Online (Sandbox Code Playgroud)

还有一些结果(关于2.12.8):

Benchmark                              Mode  Cnt        Score      Error  Units
FilterBenchmark.withCollect           thrpt   10  1359035.689 ± 2749.815  ops/s
FilterBenchmark.withCollectTypeMatch  thrpt   10  1361227.743 ± 2337.850  ops/s
FilterBenchmark.withFlatMap           thrpt   10   113074.826 ±  288.107  ops/s
FilterBenchmark.withFlatMapTypeMatch  thrpt   10   113188.419 ±  262.826  ops/s
FilterBenchmark.withIsFoo             thrpt   10  1254404.326 ± 3997.759  ops/s
FilterBenchmark.withIsInstanceOf      thrpt   10  1257725.670 ± 6115.773  ops/s
Run Code Online (Sandbox Code Playgroud)

这个故事的寓意(在我看来)是flatMap一个数量级而且明显不好,但是其他选择之间没有足够的差别来使表现与决定相关.